Line data Source code
1 : #pragma once 2 : 3 : #include "envoy/common/optref.h" 4 : #include "envoy/server/admin.h" 5 : #include "envoy/stats/stats.h" 6 : 7 : #include "source/common/buffer/buffer_impl.h" 8 : #include "source/common/json/json_streamer.h" 9 : #include "source/server/admin/stats_params.h" 10 : #include "source/server/admin/utils.h" 11 : 12 : namespace Envoy { 13 : namespace Server { 14 : 15 : // Abstract class for rendering stats. Every method is called "generate" 16 : // differing only by the data type, to facilitate templatized call-sites. 17 : // 18 : // There are currently Json and Text implementations of this interface, and in 19 : // #19546 an HTML version will be added to provide a hierarchical view. 20 : class StatsRender { 21 : public: 22 0 : virtual ~StatsRender() = default; 23 : 24 : // Writes a fragment for a numeric value, for counters and gauges. 25 : virtual void generate(Buffer::Instance& response, const std::string& name, uint64_t value) PURE; 26 : 27 : // Writes a json fragment for a textual value, for text readouts. 28 : virtual void generate(Buffer::Instance& response, const std::string& name, 29 : const std::string& value) PURE; 30 : 31 : // Writes a histogram value. 32 : virtual void generate(Buffer::Instance& response, const std::string& name, 33 : const Stats::ParentHistogram& histogram) PURE; 34 : 35 : // Completes rendering any buffered data. 36 : virtual void finalize(Buffer::Instance& response) PURE; 37 : 38 : // Indicates that no stats for a particular type have been found. 39 0 : virtual void noStats(Buffer::Instance&, absl::string_view) {} 40 : }; 41 : 42 : // Implements the Render interface for simple textual representation of stats. 43 : class StatsTextRender : public StatsRender { 44 : public: 45 : explicit StatsTextRender(const StatsParams& params); 46 : 47 : // StatsRender 48 : void generate(Buffer::Instance& response, const std::string& name, uint64_t value) override; 49 : void generate(Buffer::Instance& response, const std::string& name, 50 : const std::string& value) override; 51 : void generate(Buffer::Instance& response, const std::string& name, 52 : const Stats::ParentHistogram& histogram) override; 53 : void finalize(Buffer::Instance&) override; 54 : 55 : private: 56 : // Computes disjoint buckets as text and adds them to the response buffer. 57 : void addDisjointBuckets(const std::string& name, const Stats::ParentHistogram& histogram, 58 : Buffer::Instance& response); 59 : 60 : void addDetail(const std::vector<Stats::ParentHistogram::Bucket>& buckets, 61 : Buffer::Instance& response); 62 : 63 : const Utility::HistogramBucketsMode histogram_buckets_mode_; 64 : }; 65 : 66 : // Implements the Render interface for json output. 67 : class StatsJsonRender : public StatsRender { 68 : public: 69 : StatsJsonRender(Http::ResponseHeaderMap& response_headers, Buffer::Instance& response, 70 : const StatsParams& params); 71 : 72 : // StatsRender 73 : void generate(Buffer::Instance& response, const std::string& name, uint64_t value) override; 74 : void generate(Buffer::Instance& response, const std::string& name, 75 : const std::string& value) override; 76 : void generate(Buffer::Instance&, const std::string& name, 77 : const Stats::ParentHistogram& histogram) override; 78 : void finalize(Buffer::Instance& response) override; 79 : 80 : /** 81 : * Streams the supported percentiles into a JSON array. Note that no histogram 82 : * context is provided for this; this is a static property of the binary. 83 : * 84 : * @param array the json streaming array array to stream into. 85 : */ 86 : static void populateSupportedPercentiles(Json::Streamer::Array& array); 87 : 88 : /** 89 : * Streams detail about the provided histogram into the provided JSON map. 90 : * 91 : * @param name the name of the histogram (usually the same as histogram.name(), 92 : * but is passed in explicitly because it may already have been 93 : * computed when filtering stats, and it is somewhat expensive 94 : * to compute the name. 95 : * @param histogram the histogram to stream 96 : * @param map the json map to stream into. 97 : * 98 : */ 99 : static void generateHistogramDetail(const std::string& name, 100 : const Stats::ParentHistogram& histogram, 101 : Json::Streamer::Map& map); 102 : 103 : private: 104 : // Collects the buckets from the specified histogram. 105 : void collectBuckets(const std::string& name, const Stats::ParentHistogram& histogram, 106 : const std::vector<uint64_t>& interval_buckets, 107 : const std::vector<uint64_t>& cumulative_buckets); 108 : 109 : static void populateBucketsVerbose(const std::vector<Stats::ParentHistogram::Bucket>& buckets, 110 : Json::Streamer::Map& map); 111 : void renderHistogramStart(); 112 : static void populatePercentiles(const Stats::ParentHistogram& histogram, 113 : Json::Streamer::Map& map); 114 : 115 : // This function irons out an API mistake made when defining the StatsRender 116 : // interface. The issue is that callers can provide a response buffer when 117 : // constructing a StatsRender instance, but can switch to a different response 118 : // buffer when rendering specific values. 119 : // 120 : // The problem comes with JSON histograms where each histogram is nested in a 121 : // structure with other histograms, so if you switch buffers you need to 122 : // ensure the pending bytes in the previous buffer is fully 123 : // drained. Unfortunately this buffer-switching is used in practice. 124 : void drainIfNeeded(Buffer::Instance& response); 125 : 126 : const Utility::HistogramBucketsMode histogram_buckets_mode_; 127 : std::string name_buffer_; // Used for Json::sanitize for names. 128 : std::string value_buffer_; // Used for Json::sanitize for text-readout values. 129 : bool histograms_initialized_{false}; 130 : 131 : // Captures the hierarchy of maps and arrays used to render scalar stats and 132 : // histograms in various formats. This is separated in its own structure to 133 : // facilitate clearing these structures in the reverse order of how they were 134 : // created during finalize(). 135 : // 136 : // Another option to consider: flattening the member variables of JsonContext 137 : // into StatsJsonRender, and ensure that Render objects are always destructed 138 : // before the output stream is considered complete. 139 : struct JsonContext { 140 : explicit JsonContext(Buffer::Instance& response); 141 : Json::Streamer streamer_; 142 : Json::Streamer::MapPtr stats_map_; 143 : Json::Streamer::ArrayPtr stats_array_; 144 : Json::Streamer::MapPtr histogram_map1_; 145 : Json::Streamer::MapPtr histogram_map2_; 146 : Json::Streamer::ArrayPtr histogram_array_; 147 : }; 148 : std::unique_ptr<JsonContext> json_; 149 : Buffer::Instance& response_; 150 : }; 151 : 152 : } // namespace Server 153 : } // namespace Envoy