/proc/self/cwd/source/server/admin/stats_request.h
Line | Count | Source (jump to first uncovered line) |
1 | | #pragma once |
2 | | |
3 | | #include "envoy/server/admin.h" |
4 | | |
5 | | #include "source/server/admin/stats_params.h" |
6 | | #include "source/server/admin/stats_render.h" |
7 | | #include "source/server/admin/utils.h" |
8 | | |
9 | | #include "absl/container/btree_map.h" |
10 | | #include "absl/types/variant.h" |
11 | | |
12 | | namespace Envoy { |
13 | | namespace Server { |
14 | | |
15 | | // Captures context for a streaming request, implementing the AdminHandler interface. |
16 | | class StatsRequest : public Admin::Request { |
17 | | using ScopeVec = std::vector<Stats::ConstScopeSharedPtr>; |
18 | | using StatOrScopes = absl::variant<ScopeVec, Stats::TextReadoutSharedPtr, Stats::CounterSharedPtr, |
19 | | Stats::GaugeSharedPtr, Stats::HistogramSharedPtr>; |
20 | | |
21 | | // Ordered to match the StatsOrScopes variant. |
22 | | enum class StatOrScopesIndex { Scopes, TextReadout, Counter, Gauge, Histogram }; |
23 | | |
24 | | // In order to keep the output consistent with the fully buffered behavior |
25 | | // prior to the chunked implementation that buffered each type, we iterate |
26 | | // over all scopes for each type. This enables the complex chunking |
27 | | // implementation to pass the tests that capture the buffered behavior. There |
28 | | // is not a significant cost to this, but in a future PR we may choose to |
29 | | // co-mingle the types. Note that histograms are groups together in the data |
30 | | // JSON data model, so we won't be able to fully co-mingle. |
31 | | enum class Phase { |
32 | | TextReadouts, |
33 | | CountersAndGauges, |
34 | | Histograms, |
35 | | }; |
36 | | |
37 | | public: |
38 | | using UrlHandlerFn = std::function<Admin::UrlHandler()>; |
39 | | |
40 | | static constexpr uint64_t DefaultChunkSize = 2 * 1000 * 1000; |
41 | | |
42 | | StatsRequest(Stats::Store& stats, const StatsParams& params, |
43 | | const Upstream::ClusterManager& cluster_manager, |
44 | | UrlHandlerFn url_handler_fn = nullptr); |
45 | | |
46 | | // Admin::Request |
47 | | Http::Code start(Http::ResponseHeaderMap& response_headers) override; |
48 | | |
49 | | // Streams out the next chunk of stats to the client, visiting only the scopes |
50 | | // that can plausibly contribute the next set of named stats. This enables us |
51 | | // to linearly traverse the entire set of stats without buffering all of them |
52 | | // and sorting. |
53 | | // |
54 | | // Instead we keep the a set of candidate stats to emit in stat_map_ an |
55 | | // alphabetically ordered btree, which heterogeneously stores stats of all |
56 | | // types and scopes. Note that there can be multiple scopes with the same |
57 | | // name, so we keep same-named scopes in a vector. However leaf metrics cannot |
58 | | // have duplicates. It would also be feasible to use a multi-map for this. |
59 | | // |
60 | | // So in start() above, we initially populate all the scopes, as well as the |
61 | | // metrics contained in all scopes with an empty name. So in nextChunk we can |
62 | | // emit and remove the first element of stat_map_. When we encounter a vector |
63 | | // of scopes then we add the contained metrics to the map and continue |
64 | | // iterating. |
65 | | // |
66 | | // Whenever the desired chunk size is reached we end the current chunk so that |
67 | | // the current buffer can be flushed to the network. In #19898 we will |
68 | | // introduce flow-control so that we don't buffer the all the serialized stats |
69 | | // while waiting for a slow client. |
70 | | // |
71 | | // Note that we do 3 passes through all the scopes_, so that we can emit |
72 | | // text-readouts first, then the intermingled counters and gauges, and finally |
73 | | // the histograms. |
74 | | bool nextChunk(Buffer::Instance& response) override; |
75 | | |
76 | | // To duplicate prior behavior for this class, we do three passes over all the stats: |
77 | | // 1. text readouts across all scopes |
78 | | // 2. counters and gauges, co-mingled, across all scopes |
79 | | // 3. histograms across all scopes. |
80 | | // It would be little more efficient to co-mingle all the stats, but three |
81 | | // passes over the scopes is OK. In the future we may decide to organize the |
82 | | // result data differently, but in the process of changing from buffering |
83 | | // the entire /stats response to streaming the data out in chunks, it's easier |
84 | | // to reason about if the tests don't change their expectations. |
85 | | void startPhase(); |
86 | | |
87 | | // Iterates over scope_vec and populates the metric types associated with the |
88 | | // current phase. |
89 | | void populateStatsForCurrentPhase(const ScopeVec& scope_vec); |
90 | | |
91 | | // Populates all the metrics of the templatized type from scope_vec. Here we |
92 | | // exploit that Scope::iterate is a generic templatized function to avoid code |
93 | | // duplication. |
94 | | template <class StatType> void populateStatsFromScopes(const ScopeVec& scope_vec); |
95 | | |
96 | | void renderPerHostMetrics(Buffer::Instance& response); |
97 | | |
98 | | // Renders the templatized type, exploiting the fact that Render::generate is |
99 | | // generic to avoid code duplication. |
100 | | template <class SharedStatType> |
101 | | void renderStat(const std::string& name, Buffer::Instance& response, StatOrScopes& variant); |
102 | | |
103 | | // Sets the chunk size. |
104 | 0 | void setChunkSize(uint64_t chunk_size) { chunk_size_ = chunk_size; } |
105 | | |
106 | | private: |
107 | | StatsParams params_; |
108 | | std::unique_ptr<StatsRender> render_; |
109 | | Stats::Store& stats_; |
110 | | ScopeVec scopes_; |
111 | | absl::btree_map<std::string, StatOrScopes> stat_map_; |
112 | | Phase phase_{Phase::TextReadouts}; |
113 | | uint64_t phase_stat_count_{0}; |
114 | | absl::string_view phase_string_{"text readouts"}; |
115 | | Buffer::OwnedImpl response_; |
116 | | const Upstream::ClusterManager& cluster_manager_; |
117 | | UrlHandlerFn url_handler_fn_; |
118 | | uint64_t chunk_size_{DefaultChunkSize}; |
119 | | }; |
120 | | |
121 | | } // namespace Server |
122 | | } // namespace Envoy |