Line data Source code
1 : #pragma once 2 : 3 : #include <string> 4 : #include <vector> 5 : 6 : #include "envoy/stats/allocator.h" 7 : #include "envoy/stats/stats.h" 8 : #include "envoy/stats/tag.h" 9 : 10 : #include "source/common/common/assert.h" 11 : #include "source/common/stats/symbol_table.h" 12 : 13 : namespace Envoy { 14 : namespace Stats { 15 : 16 : /** 17 : * Helper class for implementing Metrics. This does not participate in any 18 : * inheritance chains, but can be instantiated by classes that do. It just 19 : * implements the mechanics of representing the name, tag-extracted-name, 20 : * and all tags as a StatNameList. 21 : */ 22 : class MetricHelper { 23 : public: 24 : MetricHelper(StatName name, StatName tag_extracted_name, const StatNameTagVector& stat_name_tags, 25 : SymbolTable& symbol_table); 26 : ~MetricHelper(); 27 : 28 : StatName statName() const; 29 : std::string name(const SymbolTable& symbol_table) const; 30 : TagVector tags(const SymbolTable& symbol_table) const; 31 : StatName tagExtractedStatName() const; 32 : void iterateTagStatNames(const Metric::TagStatNameIterFn& fn) const; 33 392190 : void clear(SymbolTable& symbol_table) { stat_names_.clear(symbol_table); } 34 : 35 : // Hasher for metrics. 36 : struct Hash { 37 : using is_transparent = void; // NOLINT(readability-identifier-naming) 38 750139 : size_t operator()(const Metric* a) const { return a->statName().hash(); } 39 661506 : size_t operator()(StatName a) const { return a.hash(); } 40 : }; 41 : 42 : // Comparator for metrics. 43 : struct Compare { 44 : using is_transparent = void; // NOLINT(readability-identifier-naming) 45 22684 : bool operator()(const Metric* a, const Metric* b) const { 46 22684 : return a->statName() == b->statName(); 47 22684 : } 48 355938 : bool operator()(const Metric* a, StatName b) const { return a->statName() == b; } 49 : }; 50 : 51 : private: 52 : StatNameList stat_names_; 53 : }; 54 : 55 : // An unordered set of stat pointers. which keys off Metric::statName(). 56 : // This necessitates a custom comparator and hasher, using the StatNamePtr's 57 : // own StatNamePtrHash and StatNamePtrCompare operators. 58 : // 59 : // This is used by AllocatorImpl for counters, gauges, and text-readouts, and 60 : // is also used by thread_local_store.h for histograms. 61 : template <class StatType> 62 : using StatSet = absl::flat_hash_set<StatType*, MetricHelper::Hash, MetricHelper::Compare>; 63 : 64 : /** 65 : * Partial implementation of the Metric interface on behalf of Counters, Gauges, 66 : * and Histograms. It leaves symbolTable() unimplemented so that implementations 67 : * of stats managed by an allocator, specifically Counters and Gauges, can keep 68 : * a reference to the allocator instead, and derive the symbolTable() from that. 69 : * 70 : * We templatize on the base class (Counter, Gauge, or Histogram), rather than 71 : * using multiple virtual inheritance, as this avoids the overhead of an extra 72 : * vptr per instance. This is important for stats because there can be many 73 : * stats in systems with large numbers of clusters and hosts, and a few 8-byte 74 : * pointers per-stat here and there can add up to significant amounts of memory. 75 : * 76 : * Note the delegation of the implementation to a helper class, which is neither 77 : * templatized nor virtual. This avoids having the compiler elaborate complete 78 : * copies of the underlying implementation for each base class during template 79 : * expansion. 80 : */ 81 : template <class BaseClass> class MetricImpl : public BaseClass { 82 : public: 83 : MetricImpl(StatName name, StatName tag_extracted_name, const StatNameTagVector& stat_name_tags, 84 : SymbolTable& symbol_table) 85 392190 : : helper_(name, tag_extracted_name, stat_name_tags, symbol_table) {} 86 : 87 : // Empty construction of a MetricImpl; used for null stats. 88 : explicit MetricImpl(SymbolTable& symbol_table) 89 43042 : : MetricImpl(StatName(), StatName(), StatNameTagVector(), symbol_table) {} 90 : 91 0 : TagVector tags() const override { return helper_.tags(constSymbolTable()); } 92 2412579 : StatName statName() const override { return helper_.statName(); } 93 38576 : StatName tagExtractedStatName() const override { return helper_.tagExtractedStatName(); } 94 0 : void iterateTagStatNames(const Metric::TagStatNameIterFn& fn) const override { 95 0 : helper_.iterateTagStatNames(fn); 96 0 : } 97 : 98 575706 : const SymbolTable& constSymbolTable() const override { 99 : // Cast our 'this', which is of type `const MetricImpl*` to a non-const 100 : // pointer, so we can use it to call the subclass implementation of 101 : // symbolTable(). That will be returned as a non-const SymbolTable&, 102 : // which will become const on return. 103 : // 104 : // This pattern is used to share a single non-trivial implementation to 105 : // provide const and non-const variants of a method. 106 575706 : return const_cast<MetricImpl*>(this)->symbolTable(); 107 575706 : } 108 537129 : std::string name() const override { return constSymbolTable().toString(this->statName()); } 109 38576 : std::string tagExtractedName() const override { 110 38576 : return constSymbolTable().toString(this->tagExtractedStatName()); 111 38576 : } 112 : 113 : protected: 114 392190 : void clear(SymbolTable& symbol_table) { helper_.clear(symbol_table); } 115 : 116 : private: 117 : MetricHelper helper_; 118 : }; 119 : 120 : } // namespace Stats 121 : } // namespace Envoy