/proc/self/cwd/source/common/stats/utility.h
Line | Count | Source |
1 | | #pragma once |
2 | | |
3 | | #include <string> |
4 | | |
5 | | #include "envoy/stats/scope.h" |
6 | | #include "envoy/stats/stats.h" |
7 | | |
8 | | #include "source/common/common/thread.h" |
9 | | #include "source/common/stats/symbol_table.h" |
10 | | |
11 | | #include "absl/container/inlined_vector.h" |
12 | | #include "absl/strings/string_view.h" |
13 | | #include "absl/types/optional.h" |
14 | | |
15 | | namespace Envoy { |
16 | | namespace Stats { |
17 | | |
18 | | /** |
19 | | * Represents a dynamically created stat name token based on absl::string_view. |
20 | | * This class wrapper is used in the 'Element' variant so that call-sites |
21 | | * can express explicit intent to create dynamic stat names, which are more |
22 | | * expensive than symbolic stat names. We use dynamic stat names only for |
23 | | * building stats based on names discovered in the line of a request. |
24 | | */ |
25 | | class DynamicName : public absl::string_view { |
26 | | public: |
27 | | // This is intentionally left as an implicit conversion from string_view to |
28 | | // make call-sites easier to read, e.g. |
29 | | // Utility::counterFromElements(*scope, {DynamicName("a"), DynamicName("b")}); |
30 | 8.00k | explicit DynamicName(absl::string_view str) : absl::string_view(str) {} |
31 | | }; |
32 | | |
33 | | /** |
34 | | * Represents a dynamically created stat name token based on std::string. |
35 | | * This class wrapper is used in the 'Element' variant so that call-sites |
36 | | * can express explicit intent to create dynamic stat names, which are more |
37 | | * expensive than symbolic stat names. We use dynamic stat names only for |
38 | | * building stats based on names discovered in the line of a request. |
39 | | * |
40 | | * Specifically, this class should be used only when the content of the string |
41 | | * can be changed between the object creation and usage. |
42 | | */ |
43 | | class DynamicSavedName : public std::string { |
44 | | public: |
45 | | // This is intentionally left as an implicit conversion from string_view to |
46 | | // make call-sites easier to read, e.g. |
47 | | // Utility::counterFromElements(*scope, {DynamicSavedName("a"), DynamicSavedName("b")}); |
48 | 2 | explicit DynamicSavedName(absl::string_view str) : std::string(str.begin(), str.end()) {} |
49 | | }; |
50 | | |
51 | | /** |
52 | | * Holds either a symbolic StatName or a dynamic string, for the purpose of |
53 | | * composing a vector to pass to Utility::counterFromElements, etc. This is |
54 | | * a programming convenience to create joined stat names. It is easier to |
55 | | * call the above helpers than to use SymbolTable::join(), because the helpers |
56 | | * hide the memory management of the joined storage, and they allow easier |
57 | | * co-mingling of symbolic and dynamic stat-name components. |
58 | | */ |
59 | | using Element = absl::variant<StatName, DynamicName, DynamicSavedName>; |
60 | | using ElementVec = absl::InlinedVector<Element, 8>; |
61 | | |
62 | | /** |
63 | | * Common stats utility routines. |
64 | | */ |
65 | | namespace Utility { |
66 | | /** |
67 | | * ':' is a reserved char in statsd. Do a character replacement to avoid |
68 | | * costly inline translations later. |
69 | | * |
70 | | * @param name the stat name to sanitize. |
71 | | * @return the sanitized stat name. |
72 | | */ |
73 | | std::string sanitizeStatsName(absl::string_view name); |
74 | | |
75 | | /** |
76 | | * Finds a metric tag with the specified name. |
77 | | * |
78 | | * @param metric The metric in which the tag is expected to exist. |
79 | | * @param find_tag_name The name of the tag to search for. |
80 | | * @return The value of the tag, if found. |
81 | | */ |
82 | | absl::optional<StatName> findTag(const Metric& metric, StatName find_tag_name); |
83 | | |
84 | | /** |
85 | | * Creates a nested scope from a vector of StatNames which are used to create the |
86 | | * name. |
87 | | * |
88 | | * See also scopeFromElements, which is slightly slower but allows |
89 | | * passing DynamicName(string)s as names. |
90 | | * |
91 | | * @param scope The scope in which to create the counter. |
92 | | * @param elements The vector of mixed DynamicName and StatName |
93 | | * @return A scope named using the joined elements. |
94 | | */ |
95 | | ScopeSharedPtr scopeFromStatNames(Scope& scope, const StatNameVec& names); |
96 | | |
97 | | /** |
98 | | * Creates a counter from a vector of tokens which are used to create the |
99 | | * name. The tokens can be specified as DynamicName or StatName. For |
100 | | * tokens specified as DynamicName, a dynamic StatName will be created. See |
101 | | * https://github.com/envoyproxy/envoy/blob/main/source/docs/stats.md#dynamic-stat-tokens |
102 | | * for more detail on why symbolic StatNames are preferred when possible. |
103 | | * |
104 | | * See also counterFromStatNames, which is slightly faster but does not allow |
105 | | * passing DynamicName(string)s as names. |
106 | | * |
107 | | * @param scope The scope in which to create the counter. |
108 | | * @param elements The vector of mixed DynamicName and StatName |
109 | | * @param tags optionally specified tags. |
110 | | * @return A counter named using the joined elements. |
111 | | */ |
112 | | Counter& counterFromElements(Scope& scope, const ElementVec& elements, |
113 | | StatNameTagVectorOptConstRef tags = absl::nullopt); |
114 | | |
115 | | /** |
116 | | * Creates a counter from a vector of tokens which are used to create the |
117 | | * name. The tokens must be of type StatName. |
118 | | * |
119 | | * See also counterFromElements, which is slightly slower, but allows |
120 | | * passing DynamicName(string)s as elements. |
121 | | * |
122 | | * @param scope The scope in which to create the counter. |
123 | | * @param names The vector of StatNames |
124 | | * @param tags optionally specified tags. |
125 | | * @return A counter named using the joined elements. |
126 | | */ |
127 | | Counter& counterFromStatNames(Scope& scope, const StatNameVec& names, |
128 | | StatNameTagVectorOptConstRef tags = absl::nullopt); |
129 | | |
130 | | /** |
131 | | * Creates a gauge from a vector of tokens which are used to create the |
132 | | * name. The tokens can be specified as DynamicName or StatName. For |
133 | | * tokens specified as DynamicName, a dynamic StatName will be created. See |
134 | | * https://github.com/envoyproxy/envoy/blob/main/source/docs/stats.md#dynamic-stat-tokens |
135 | | * for more detail on why symbolic StatNames are preferred when possible. |
136 | | * |
137 | | * See also gaugeFromStatNames, which is slightly faster but does not allow |
138 | | * passing DynamicName(string)s as names. |
139 | | * |
140 | | * @param scope The scope in which to create the counter. |
141 | | * @param elements The vector of mixed DynamicName and StatName |
142 | | * @param import_mode Whether hot-restart should accumulate this value. |
143 | | * @param tags optionally specified tags. |
144 | | * @return A gauge named using the joined elements. |
145 | | */ |
146 | | Gauge& gaugeFromElements(Scope& scope, const ElementVec& elements, Gauge::ImportMode import_mode, |
147 | | StatNameTagVectorOptConstRef tags = absl::nullopt); |
148 | | |
149 | | /** |
150 | | * Creates a gauge from a vector of tokens which are used to create the |
151 | | * name. The tokens must be of type StatName. |
152 | | * |
153 | | * See also gaugeFromElements, which is slightly slower, but allows |
154 | | * passing DynamicName(string)s as elements. |
155 | | * |
156 | | * @param scope The scope in which to create the counter. |
157 | | * @param names The vector of StatNames |
158 | | * @param import_mode Whether hot-restart should accumulate this value. |
159 | | * @param tags optionally specified tags. |
160 | | * @return A gauge named using the joined elements. |
161 | | */ |
162 | | Gauge& gaugeFromStatNames(Scope& scope, const StatNameVec& elements, Gauge::ImportMode import_mode, |
163 | | StatNameTagVectorOptConstRef tags = absl::nullopt); |
164 | | |
165 | | /** |
166 | | * Creates a histogram from a vector of tokens which are used to create the |
167 | | * name. The tokens can be specified as DynamicName or StatName. For |
168 | | * tokens specified as DynamicName, a dynamic StatName will be created. See |
169 | | * https://github.com/envoyproxy/envoy/blob/main/source/docs/stats.md#dynamic-stat-tokens |
170 | | * for more detail on why symbolic StatNames are preferred when possible. |
171 | | * |
172 | | * See also histogramFromStatNames, which is slightly faster but does not allow |
173 | | * passing DynamicName(string)s as names. |
174 | | * |
175 | | * @param scope The scope in which to create the counter. |
176 | | * @param elements The vector of mixed DynamicName and StatName |
177 | | * @param unit The unit of measurement. |
178 | | * @param tags optionally specified tags. |
179 | | * @return A histogram named using the joined elements. |
180 | | */ |
181 | | Histogram& histogramFromElements(Scope& scope, const ElementVec& elements, Histogram::Unit unit, |
182 | | StatNameTagVectorOptConstRef tags = absl::nullopt); |
183 | | |
184 | | /** |
185 | | * Creates a histogram from a vector of tokens which are used to create the |
186 | | * name. The tokens must be of type StatName. |
187 | | * |
188 | | * See also histogramFromElements, which is slightly slower, but allows |
189 | | * passing DynamicName(string)s as elements. |
190 | | * |
191 | | * @param scope The scope in which to create the counter. |
192 | | * @param elements The vector of mixed DynamicName and StatName |
193 | | * @param unit The unit of measurement. |
194 | | * @param tags optionally specified tags. |
195 | | * @return A histogram named using the joined elements. |
196 | | */ |
197 | | Histogram& histogramFromStatNames(Scope& scope, const StatNameVec& elements, Histogram::Unit unit, |
198 | | StatNameTagVectorOptConstRef tags = absl::nullopt); |
199 | | |
200 | | /** |
201 | | * Creates a TextReadout from a vector of tokens which are used to create the |
202 | | * name. The tokens can be specified as DynamicName or StatName. For |
203 | | * tokens specified as DynamicName, a dynamic StatName will be created. See |
204 | | * https://github.com/envoyproxy/envoy/blob/main/source/docs/stats.md#dynamic-stat-tokens |
205 | | * for more detail on why symbolic StatNames are preferred when possible. |
206 | | * |
207 | | * See also TextReadoutFromStatNames, which is slightly faster but does not allow |
208 | | * passing DynamicName(string)s as names. |
209 | | * |
210 | | * @param scope The scope in which to create the counter. |
211 | | * @param elements The vector of mixed DynamicName and StatName |
212 | | * @param unit The unit of measurement. |
213 | | * @param tags optionally specified tags. |
214 | | * @return A TextReadout named using the joined elements. |
215 | | */ |
216 | | TextReadout& textReadoutFromElements(Scope& scope, const ElementVec& elements, |
217 | | StatNameTagVectorOptConstRef tags = absl::nullopt); |
218 | | |
219 | | /** |
220 | | * Creates a TextReadout from a vector of tokens which are used to create the |
221 | | * name. The tokens must be of type StatName. |
222 | | * |
223 | | * See also TextReadoutFromElements, which is slightly slower, but allows |
224 | | * passing DynamicName(string)s as elements. |
225 | | * |
226 | | * @param scope The scope in which to create the counter. |
227 | | * @param elements The vector of mixed DynamicName and StatName |
228 | | * @param unit The unit of measurement. |
229 | | * @param tags optionally specified tags. |
230 | | * @return A TextReadout named using the joined elements. |
231 | | */ |
232 | | TextReadout& textReadoutFromStatNames(Scope& scope, const StatNameVec& elements, |
233 | | StatNameTagVectorOptConstRef tags = absl::nullopt); |
234 | | |
235 | | } // namespace Utility |
236 | | |
237 | | /** |
238 | | * Holds a reference to a stat by name. Note that the stat may not be created |
239 | | * yet at the time CachedReference is created. Calling get() then does a lazy |
240 | | * lookup, potentially returning absl::nullopt if the stat doesn't exist yet. |
241 | | * StatReference works whether the name was constructed symbolically, or with |
242 | | * StatNameDynamicStorage. |
243 | | * |
244 | | * Lookups are very slow, taking time proportional to the size of the scope, |
245 | | * holding mutexes during the lookup. However once the lookup succeeds, the |
246 | | * result is cached atomically, and further calls to get() are thus fast and |
247 | | * mutex-free. The implementation may be faster for stats that are named |
248 | | * symbolically. |
249 | | * |
250 | | * CachedReference is valid for the lifetime of the Scope. When the Scope |
251 | | * becomes invalid, CachedReferences must also be dropped as they will hold |
252 | | * pointers into the scope. |
253 | | */ |
254 | | template <class StatType> class CachedReference { |
255 | | public: |
256 | | CachedReference(Scope& scope, absl::string_view name) : scope_(scope), name_(std::string(name)) {} |
257 | | |
258 | | /** |
259 | | * Finds the named stat, if it exists, returning it as an optional. |
260 | | */ |
261 | | absl::optional<std::reference_wrapper<StatType>> get() { |
262 | | StatType* stat = stat_.get([this]() -> StatType* { |
263 | | StatType* stat = nullptr; |
264 | | IterateFn<StatType> check_stat = [this, |
265 | | &stat](const RefcountPtr<StatType>& shared_stat) -> bool { |
266 | | if (shared_stat->name() == name_) { |
267 | | stat = shared_stat.get(); |
268 | | return false; // Stop iteration. |
269 | | } |
270 | | return true; |
271 | | }; |
272 | | scope_.iterate(check_stat); |
273 | | return stat; |
274 | | }); |
275 | | if (stat == nullptr) { |
276 | | return absl::nullopt; |
277 | | } |
278 | | return *stat; |
279 | | } |
280 | | |
281 | | private: |
282 | | Scope& scope_; |
283 | | const std::string name_; |
284 | | Thread::AtomicPtr<StatType, Thread::AtomicPtrAllocMode::DoNotDelete> stat_; |
285 | | }; |
286 | | |
287 | | } // namespace Stats |
288 | | } // namespace Envoy |