1
#pragma once
2

            
3
#include <cstdint>
4
#include <functional>
5
#include <memory>
6

            
7
#include "envoy/common/pure.h"
8
#include "envoy/stats/histogram.h"
9
#include "envoy/stats/stats_matcher.h"
10
#include "envoy/stats/tag.h"
11

            
12
#include "absl/types/optional.h"
13

            
14
namespace Envoy {
15
namespace Stats {
16

            
17
class Counter;
18
class Gauge;
19
class Histogram;
20
class NullGaugeImpl;
21
class Scope;
22
class Store;
23
class TextReadout;
24

            
25
using CounterOptConstRef = absl::optional<std::reference_wrapper<const Counter>>;
26
using GaugeOptConstRef = absl::optional<std::reference_wrapper<const Gauge>>;
27
using HistogramOptConstRef = absl::optional<std::reference_wrapper<const Histogram>>;
28
using TextReadoutOptConstRef = absl::optional<std::reference_wrapper<const TextReadout>>;
29
using ConstScopeSharedPtr = std::shared_ptr<const Scope>;
30
using ScopeSharedPtr = std::shared_ptr<Scope>;
31

            
32
// Settings for limiting the number of counters, gauges and histograms allowed
33
// in a scope. This currently only supports thread local stats.
34
struct ScopeStatsLimitSettings {
35
  // Max number of counters allowed in this scope. 0 means no limit.
36
  uint32_t max_counters = 0;
37
  // Max number of gauges allowed in this scope. 0 means no limit.
38
  uint32_t max_gauges = 0;
39
  // Max number of histograms allowed in this scope. 0 means no limit.
40
  uint32_t max_histograms = 0;
41
};
42

            
43
template <class StatType> using IterateFn = std::function<bool(const RefcountPtr<StatType>&)>;
44

            
45
/**
46
 * A named scope for stats. Scopes are a grouping of stats that can be acted on
47
 * as a unit if needed (for example to free/delete all of them).
48
 *
49
 * Every counters, gauges, histograms, and text-readouts is managed by a Scope.
50
 *
51
 * Scopes are managed by shared pointers. This makes it possible for the admin
52
 * stats handler to safely capture all the scope references and remain robust to
53
 * other threads deleting those scopes while rendering an admin stats page.
54
 *
55
 * It is invalid to allocate a Scope using std::unique_ptr or directly on the
56
 * stack.
57
 *
58
 * We use std::shared_ptr rather than Stats::RefcountPtr, which we use for other
59
 * stats, because:
60
 *  * existing uses of shared_ptr<Scope> exist in the Wasm extension and would
61
 *    need to be rewritten to allow for RefcountPtr<Scope>.
62
 *  * the main advantage of RefcountPtr is it's smaller per instance by 16
63
 *    bytes, but there are not typically enough scopes that the extra per-scope
64
 *    overhead would matter.
65
 *  * It's a little less coding to use enable_shared_from_this compared to
66
 *    adding a ref_count to the scope object, for each of its implementations.
67
 */
68
class Scope : public std::enable_shared_from_this<Scope> {
69
public:
70
2125187
  virtual ~Scope() = default;
71

            
72
  /** @return a shared_ptr for this */
73
  ScopeSharedPtr getShared() { return shared_from_this(); }
74

            
75
  /** @return a const shared_ptr for this */
76
39142
  ConstScopeSharedPtr getConstShared() const { return shared_from_this(); }
77

            
78
  /**
79
   * Allocate a new scope. NOTE: The implementation should correctly handle overlapping scopes
80
   * that point to the same reference counted backing stats. This allows a new scope to be
81
   * gracefully swapped in while an old scope with the same name is being destroyed.
82
   *
83
   * See also scopeFromStatName, which is preferred.
84
   *
85
   * @param name supplies the scope's namespace prefix.
86
   * @param evictable whether unused metrics can be deleted from the scope caches. This requires
87
   * that the metrics are not stored by reference.
88
   * @param limits metric limits for counters, gauges and histograms allowed in this scope.
89
   * @param matcher optional per-scope stats matcher; replaces the store-level matcher when set.
90
   * NOTE: If the scope specific matcher is set, then the sub scope will inherit the same matcher
91
   * unless another matcher is explicitly set.
92
   */
93
  virtual ScopeSharedPtr createScope(const std::string& name, bool evictable = false,
94
                                     const ScopeStatsLimitSettings& limits = {},
95
                                     StatsMatcherSharedPtr matcher = nullptr) PURE;
96

            
97
  /**
98
   * Allocate a new scope. NOTE: The implementation should correctly handle overlapping scopes
99
   * that point to the same reference counted backing stats. This allows a new scope to be
100
   * gracefully swapped in while an old scope with the same name is being destroyed.
101
   *
102
   * @param name supplies the scope's namespace prefix.
103
   * @param evictable whether unused metrics can be deleted from the scope caches. This requires
104
   * that the metrics are not stored by reference.
105
   * @param limits metric limits for counters, gauges and histograms allowed in this scope.
106
   * @param matcher optional per-scope stats matcher; replaces the store-level matcher when set.
107
   * NOTE: If the scope specific matcher is set, then the sub scope will inherit the same matcher
108
   * unless another matcher is explicitly set.
109
   */
110
  virtual ScopeSharedPtr scopeFromStatName(StatName name, bool evictable = false,
111
                                           const ScopeStatsLimitSettings& limits = {},
112
                                           StatsMatcherSharedPtr matcher = nullptr) PURE;
113

            
114
  /**
115
   * Creates a Counter from the stat name. Tag extraction will be performed on the name.
116
   * @param name The name of the stat, obtained from the SymbolTable.
117
   * @return a counter within the scope's namespace.
118
   */
119
4228398
  Counter& counterFromStatName(const StatName& name) {
120
4228398
    return counterFromStatNameWithTags(name, absl::nullopt);
121
4228398
  }
122
  /**
123
   * Creates a Counter from the stat name and tags. If tags are not provided, tag extraction
124
   * will be performed on the name.
125
   * @param name The name of the stat, obtained from the SymbolTable.
126
   * @param tags optionally specified tags.
127
   * @return a counter within the scope's namespace.
128
   */
129
  virtual Counter& counterFromStatNameWithTags(const StatName& name,
130
                                               StatNameTagVectorOptConstRef tags) PURE;
131

            
132
  /**
133
   * TODO(#6667): this variant is deprecated: use counterFromStatName.
134
   * @param name The name, expressed as a string.
135
   * @return a counter within the scope's namespace.
136
   */
137
  virtual Counter& counterFromString(const std::string& name) PURE;
138

            
139
  /**
140
   * Creates a Gauge from the stat name. Tag extraction will be performed on the name.
141
   * @param name The name of the stat, obtained from the SymbolTable.
142
   * @param import_mode Whether hot-restart should accumulate this value.
143
   * @return a gauge within the scope's namespace.
144
   */
145
827569
  Gauge& gaugeFromStatName(const StatName& name, Gauge::ImportMode import_mode) {
146
827569
    return gaugeFromStatNameWithTags(name, absl::nullopt, import_mode);
147
827569
  }
148

            
149
  /**
150
   * Creates a Gauge from the stat name and tags. If tags are not provided, tag extraction
151
   * will be performed on the name.
152
   * @param name The name of the stat, obtained from the SymbolTable.
153
   * @param tags optionally specified tags.
154
   * @param import_mode Whether hot-restart should accumulate this value.
155
   * @return a gauge within the scope's namespace.
156
   */
157
  virtual Gauge& gaugeFromStatNameWithTags(const StatName& name, StatNameTagVectorOptConstRef tags,
158
                                           Gauge::ImportMode import_mode) PURE;
159

            
160
  /**
161
   * TODO(#6667): this variant is deprecated: use gaugeFromStatName.
162
   * @param name The name, expressed as a string.
163
   * @param import_mode Whether hot-restart should accumulate this value.
164
   * @return a gauge within the scope's namespace.
165
   */
166
  virtual Gauge& gaugeFromString(const std::string& name, Gauge::ImportMode import_mode) PURE;
167

            
168
  /**
169
   * Creates a Histogram from the stat name. Tag extraction will be performed on the name.
170
   * @param name The name of the stat, obtained from the SymbolTable.
171
   * @param unit The unit of measurement.
172
   * @return a histogram within the scope's namespace with a particular value type.
173
   */
174
314769
  Histogram& histogramFromStatName(const StatName& name, Histogram::Unit unit) {
175
314769
    return histogramFromStatNameWithTags(name, absl::nullopt, unit);
176
314769
  }
177

            
178
  /**
179
   * Creates a Histogram from the stat name and tags. If tags are not provided, tag extraction
180
   * will be performed on the name.
181
   * @param name The name of the stat, obtained from the SymbolTable.
182
   * @param tags optionally specified tags.
183
   * @param unit The unit of measurement.
184
   * @return a histogram within the scope's namespace with a particular value type.
185
   */
186
  virtual Histogram& histogramFromStatNameWithTags(const StatName& name,
187
                                                   StatNameTagVectorOptConstRef tags,
188
                                                   Histogram::Unit unit) PURE;
189

            
190
  /**
191
   * TODO(#6667): this variant is deprecated: use histogramFromStatName.
192
   * @param name The name, expressed as a string.
193
   * @param unit The unit of measurement.
194
   * @return a histogram within the scope's namespace with a particular value type.
195
   */
196
  virtual Histogram& histogramFromString(const std::string& name, Histogram::Unit unit) PURE;
197

            
198
  /**
199
   * Creates a TextReadout from the stat name. Tag extraction will be performed on the name.
200
   * @param name The name of the stat, obtained from the SymbolTable.
201
   * @return a text readout within the scope's namespace.
202
   */
203
15217
  TextReadout& textReadoutFromStatName(const StatName& name) {
204
15217
    return textReadoutFromStatNameWithTags(name, absl::nullopt);
205
15217
  }
206

            
207
  /**
208
   * Creates a TextReadout from the stat name and tags. If tags are not provided, tag extraction
209
   * will be performed on the name.
210
   * @param name The name of the stat, obtained from the SymbolTable.
211
   * @param tags optionally specified tags.
212
   * @return a text readout within the scope's namespace.
213
   */
214
  virtual TextReadout& textReadoutFromStatNameWithTags(const StatName& name,
215
                                                       StatNameTagVectorOptConstRef tags) PURE;
216

            
217
  /**
218
   * TODO(#6667): this variant is deprecated: use textReadoutFromStatName.
219
   * @param name The name, expressed as a string.
220
   * @return a text readout within the scope's namespace.
221
   */
222
  virtual TextReadout& textReadoutFromString(const std::string& name) PURE;
223

            
224
  /**
225
   * @param The name of the stat, obtained from the SymbolTable.
226
   * @return a reference to a counter within the scope's namespace, if it exists.
227
   */
228
  virtual CounterOptConstRef findCounter(StatName name) const PURE;
229

            
230
  /**
231
   * @param The name of the stat, obtained from the SymbolTable.
232
   * @return a reference to a gauge within the scope's namespace, if it exists.
233
   */
234
  virtual GaugeOptConstRef findGauge(StatName name) const PURE;
235

            
236
  /**
237
   * @param The name of the stat, obtained from the SymbolTable.
238
   * @return a reference to a histogram within the scope's namespace, if it
239
   * exists.
240
   */
241
  virtual HistogramOptConstRef findHistogram(StatName name) const PURE;
242

            
243
  /**
244
   * @param The name of the stat, obtained from the SymbolTable.
245
   * @return a reference to a text readout within the scope's namespace, if it exists.
246
   */
247
  virtual TextReadoutOptConstRef findTextReadout(StatName name) const PURE;
248

            
249
  /**
250
   * @return a reference to the symbol table.
251
   */
252
  virtual const SymbolTable& constSymbolTable() const PURE;
253
  virtual SymbolTable& symbolTable() PURE;
254

            
255
  /**
256
   * Calls 'fn' for every counter. Iteration stops if `fn` returns false;
257
   *
258
   * @param fn Function to be run for every counter, or until fn return false.
259
   * @return false if fn(counter) return false during iteration, true if every counter was hit.
260
   */
261
  virtual bool iterate(const IterateFn<Counter>& fn) const PURE;
262

            
263
  /**
264
   * Calls 'fn' for every gauge. Iteration stops if `fn` returns false;
265
   *
266
   * @param fn Function to be run for every gauge, or until fn return false.
267
   * @return false if fn(gauge) return false during iteration, true if every gauge was hit.
268
   */
269
  virtual bool iterate(const IterateFn<Gauge>& fn) const PURE;
270

            
271
  /**
272
   * Calls 'fn' for every histogram. Iteration stops if `fn` returns false;
273
   *
274
   * @param fn Function to be run for every histogram, or until fn return false.
275
   * @return false if fn(histogram) return false during iteration, true if every histogram was hit.
276
   */
277
  virtual bool iterate(const IterateFn<Histogram>& fn) const PURE;
278

            
279
  /**
280
   * Calls 'fn' for every text readout. Note that in the case of overlapping
281
   * scopes, the implementation may call fn more than one time for each
282
   * text readout. Iteration stops if `fn` returns false;
283
   *
284
   * @param fn Function to be run for every text readout, or until fn return false.
285
   * @return false if fn(text_readout) return false during iteration, true if every text readout
286
   *         was hit.
287
   */
288
  virtual bool iterate(const IterateFn<TextReadout>& fn) const PURE;
289

            
290
  /**
291
   * @return the aggregated prefix for this scope. A trailing dot is not
292
   * included, even if one was supplied when creating the scope. If this is a
293
   * nested scope, it will include names from every level. E.g.
294
   *     store.createScope("foo").createScope("bar").prefix() will be the StatName "foo.bar"
295
   */
296
  virtual StatName prefix() const PURE;
297

            
298
  /**
299
   * @return a reference to the Store object that owns this scope.
300
   */
301
  virtual Store& store() PURE;
302
  virtual const Store& constStore() const PURE;
303
};
304

            
305
} // namespace Stats
306
} // namespace Envoy