Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/server/admin/stats_render.h
Line
Count
Source (jump to first uncovered line)
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