1
#pragma once
2

            
3
#include <cstdint>
4
#include <memory>
5
#include <string>
6
#include <vector>
7

            
8
#include "envoy/common/pure.h"
9
#include "envoy/stats/refcount_ptr.h"
10
#include "envoy/stats/tag.h"
11

            
12
#include "absl/strings/string_view.h"
13

            
14
namespace Envoy {
15
namespace Stats {
16

            
17
/**
18
 * Runtime representation of an encoded stat name.
19
 */
20
class StatName;
21

            
22
/**
23
 * Holds a set of symbols used to compose hierarchical names.
24
 */
25
class SymbolTable;
26

            
27
/**
28
 * General interface for all stats objects.
29
 *
30
 * Note: some methods must match those in `PrimitiveMetricMetadata` because stats sinks
31
 * use templates to handle either type. The interface is not used for size/performance
32
 * reasons.
33
 */
34
class Metric : public RefcountInterface {
35
public:
36
44353963
  ~Metric() override = default;
37
  /**
38
   * Returns the full name of the Metric. This is intended for most uses, such
39
   * as streaming out the name to a stats sink or admin request, or comparing
40
   * against it in a test. Independent of the evolution of the data
41
   * representation for the name, this method will be available.
42
   */
43
  virtual std::string name() const PURE;
44

            
45
  /**
46
   * Returns the full name of the Metric as an encoded array of symbols.
47
   */
48
  virtual StatName statName() const PURE;
49

            
50
  /**
51
   * Returns a vector of configurable tags to identify this Metric.
52
   */
53
  virtual TagVector tags() const PURE;
54

            
55
  /**
56
   * See a more detailed description in tagExtractedStatName(), which is the
57
   * preferred API to use when feasible. This API needs to compose the
58
   * std::string on the fly, and return it by value.
59
   *
60
   * @return The stat name with all tag values extracted, as a std::string.
61
   */
62
  virtual std::string tagExtractedName() const PURE;
63

            
64
  /**
65
   * Returns the name of the Metric with the portions designated as tags removed
66
   * as a string. For example, The stat name "vhost.foo.vcluster.bar.c1" would
67
   * have "foo" extracted as the value of tag "vhost" and "bar" extracted as the
68
   * value of tag "vcluster". Thus the tagExtractedName is simply
69
   * "vhost.vcluster.c1".
70
   *
71
   * @return the name of the Metric with the portions designated as tags
72
   *     removed.
73
   */
74
  virtual StatName tagExtractedStatName() const PURE;
75

            
76
  // Function to be called from iterateTagStatNames passing name and value as StatNames.
77
  using TagStatNameIterFn = std::function<bool(StatName, StatName)>;
78

            
79
  /**
80
   * Iterates over all tags, calling a functor for each name/value pair. The
81
   * functor can return 'true' to continue or 'false' to stop the
82
   * iteration.
83
   *
84
   * @param fn The functor to call for StatName pair.
85
   */
86
  virtual void iterateTagStatNames(const TagStatNameIterFn& fn) const PURE;
87

            
88
  // Function to be called from iterateTags passing name and value as const Tag&.
89
  using TagIterFn = std::function<bool(const Tag&)>;
90

            
91
  /**
92
   * Indicates whether this metric has been updated since the server was started.
93
   */
94
  virtual bool used() const PURE;
95

            
96
  /**
97
   * Clear any indicator on whether this metric has been updated.
98
   */
99
  virtual void markUnused() PURE;
100

            
101
  /**
102
   * Indicates whether this metric is hidden.
103
   */
104
  virtual bool hidden() const PURE;
105

            
106
  /**
107
   * Flags:
108
   * Used: used by all stats types to figure out whether they have been used.
109
   * Logic...: used by gauges to cache how they should be combined with a parent's value.
110
   */
111
  struct Flags {
112
    static constexpr uint8_t Used = 0x01;
113
    static constexpr uint8_t LogicAccumulate = 0x02;
114
    static constexpr uint8_t NeverImport = 0x04;
115
    static constexpr uint8_t Hidden = 0x08;
116
  };
117
  virtual SymbolTable& symbolTable() PURE;
118
  virtual const SymbolTable& constSymbolTable() const PURE;
119
};
120

            
121
/**
122
 * An always incrementing counter with latching capability. Each increment is added both to a
123
 * global counter as well as periodic counter. Calling latch() returns the periodic counter and
124
 * clears it.
125
 */
126
class Counter : public Metric {
127
public:
128
29162115
  ~Counter() override = default;
129

            
130
  virtual void add(uint64_t amount) PURE;
131
  virtual void inc() PURE;
132
  virtual uint64_t latch() PURE;
133
  virtual void reset() PURE;
134
  virtual uint64_t value() const PURE;
135
};
136

            
137
using CounterSharedPtr = RefcountPtr<Counter>;
138

            
139
/**
140
 * A gauge that can both increment and decrement.
141
 */
142
class Gauge : public Metric {
143
public:
144
  // TODO(diazalan): Rename ImportMode to more generic name
145
  enum class ImportMode {
146
    Uninitialized,    // Gauge was discovered during hot-restart transfer.
147
    NeverImport,      // On hot-restart, each process starts with gauge at 0.
148
    Accumulate,       // Transfers gauge state on hot-restart.
149
    HiddenAccumulate, // Will be transferred on hot-restart and ignored by admin/stats-sink
150
  };
151

            
152
8621634
  ~Gauge() override = default;
153

            
154
  virtual void add(uint64_t amount) PURE;
155
  virtual void dec() PURE;
156
  virtual void inc() PURE;
157
  virtual void set(uint64_t value) PURE;
158
  virtual void sub(uint64_t amount) PURE;
159
  // When adjusting a gauge both ways (e.g. buffer size update when simultaneously
160
  // streaming in and out), using this helper avoids touching the atomic twice.
161
144
  inline void adjust(uint64_t add_amount, uint64_t sub_amount) {
162
144
    if (add_amount > sub_amount) {
163
130
      add(add_amount - sub_amount);
164
130
    } else {
165
14
      sub(sub_amount - add_amount);
166
14
    }
167
144
  }
168
  virtual uint64_t value() const PURE;
169

            
170
  /**
171
   * Sets a value from a hot-restart parent. This parent contribution must be
172
   * kept distinct from the child value, so that when we erase the value it
173
   * is not commingled with the child value, which may have been set() directly.
174
   *
175
   * @param parent_value the value from the hot-restart parent.
176
   */
177
  virtual void setParentValue(uint64_t parent_value) PURE;
178

            
179
  /**
180
   * @return the import mode, dictating behavior of the gauge across hot restarts.
181
   */
182
  virtual ImportMode importMode() const PURE;
183

            
184
  /**
185
   * Gauges can be created with ImportMode::Uninitialized during hot-restart
186
   * merges, if they haven't yet been instantiated by the child process. When
187
   * they finally get instantiated, mergeImportMode should be called to
188
   * initialize the gauge's import mode. It is only valid to call
189
   * mergeImportMode when the current mode is ImportMode::Uninitialized.
190
   *
191
   * @param import_mode the new import mode.
192
   */
193
  virtual void mergeImportMode(ImportMode import_mode) PURE;
194
};
195

            
196
using GaugeSharedPtr = RefcountPtr<Gauge>;
197

            
198
/**
199
 * A string, possibly non-ASCII.
200
 */
201
class TextReadout : public virtual Metric {
202
public:
203
  // Text readout type is used internally to disambiguate isolated store
204
  // constructors. In the future we can extend it to specify text encoding or
205
  // some such.
206
  enum class Type {
207
    Default, // No particular meaning.
208
  };
209

            
210
1851348
  ~TextReadout() override = default;
211

            
212
  /**
213
   * Sets the value of this TextReadout by moving the input |value| to minimize
214
   * buffer copies under the lock.
215
   */
216
  virtual void set(absl::string_view value) PURE;
217
  /**
218
   * @return the copy of this TextReadout value.
219
   */
220
  virtual std::string value() const PURE;
221
};
222

            
223
using TextReadoutSharedPtr = RefcountPtr<TextReadout>;
224

            
225
/**
226
 * Callback invoked to provide size of stats container.
227
 */
228
using SizeFn = std::function<void(std::size_t)>;
229

            
230
/**
231
 * Callback invoked for each stat during iteration.
232
 */
233
template <typename Stat> using StatFn = std::function<void(Stat&)>;
234

            
235
/**
236
 * Interface for stats lazy initialization.
237
 * To save memory and CPU consumption on blocks of stats that are never referenced throughout the
238
 * process lifetime, they can be encapsulated in a DeferredCreationCompatibleInterface. Then the
239
Envoy
240
 * bootstrap configuration can be set to defer the instantiation of those block. Note that when the
241
 * blocks of stats are created, they carry an extra 60~100 byte overhead (depending on worker thread
242
 * count) due to internal bookkeeping data structures. The overhead when deferred stats are disabled
243
 * is just 8 bytes.
244
* See more context: https://github.com/envoyproxy/envoy/issues/23575
245
 */
246
template <typename StatsStructType> class DeferredCreationCompatibleInterface {
247
public:
248
  /**
249
   * Returns an already existing StatsStructType, or creates a new one and returns it.
250
   *
251
   * @return The new or already existing StatsStructType.
252
   */
253
  virtual StatsStructType& getOrCreate() PURE;
254

            
255
  /**
256
   * Returns whether or not the underlying stats have been initialized yet.
257
   *
258
   * @return If the underlying stats have been initialized.
259
   */
260
  virtual bool isPresent() const PURE;
261

            
262
246457
  virtual ~DeferredCreationCompatibleInterface() = default;
263
};
264

            
265
// A helper class for a lazy compatible stats struct type.
266
template <typename StatsStructType> class DeferredCreationCompatibleStats {
267
public:
268
  explicit DeferredCreationCompatibleStats(
269
      std::unique_ptr<DeferredCreationCompatibleInterface<StatsStructType>> d)
270
246457
      : data_(std::move(d)) {}
271
  // Allows move construct and assign.
272
  DeferredCreationCompatibleStats& operator=(DeferredCreationCompatibleStats&&) noexcept = default;
273
6
  DeferredCreationCompatibleStats(DeferredCreationCompatibleStats&&) noexcept = default;
274

            
275
815513
  inline StatsStructType* operator->() { return &data_->getOrCreate(); };
276
147618
  inline StatsStructType& operator*() { return data_->getOrCreate(); };
277

            
278
  /**
279
   * Returns whether or not the underlying data_ has been initialized yet.
280
   *
281
   * @return If the underlying data_ has been initialized.
282
   */
283
6
  bool isPresent() const { return data_->isPresent(); }
284

            
285
private:
286
  std::unique_ptr<DeferredCreationCompatibleInterface<StatsStructType>> data_;
287
};
288

            
289
class StatMatchingData {
290
public:
291
16
  static absl::string_view name() { return "stat_matching_data"; }
292

            
293
  virtual std::string fullName() const PURE;
294

            
295
  virtual ~StatMatchingData() = default;
296
};
297

            
298
class StatTagMatchingData {
299
public:
300
16
  static absl::string_view name() { return "stat_tag_matching_data"; }
301

            
302
  virtual absl::string_view value() const PURE;
303

            
304
  virtual ~StatTagMatchingData() = default;
305
};
306

            
307
template <class StatType> class StatMatchingDataImpl : public StatMatchingData {
308
public:
309
2308
  explicit StatMatchingDataImpl(const StatType& metric) : metric_(metric) {}
310

            
311
  static std::string name() { return "stat_matching_data_impl"; }
312

            
313
1329
  std::string fullName() const override { return metric_.name(); }
314

            
315
private:
316
  const StatType& metric_;
317
};
318

            
319
} // namespace Stats
320
} // namespace Envoy