1 // Copyright 2024 The gRPC Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef GRPC_SRC_CORE_TELEMETRY_METRICS_H
16 #define GRPC_SRC_CORE_TELEMETRY_METRICS_H
17
18 #include <grpc/support/metrics.h>
19 #include <grpc/support/port_platform.h>
20
21 #include <cstdint>
22 #include <memory>
23 #include <type_traits>
24 #include <vector>
25
26 #include "absl/functional/any_invocable.h"
27 #include "absl/functional/function_ref.h"
28 #include "absl/strings/string_view.h"
29 #include "absl/types/span.h"
30 #include "src/core/lib/channel/channel_args.h"
31 #include "src/core/lib/slice/slice.h"
32 #include "src/core/telemetry/call_tracer.h"
33 #include "src/core/util/no_destruct.h"
34 #include "src/core/util/sync.h"
35 #include "src/core/util/time.h"
36
37 namespace grpc_core {
38
39 constexpr absl::string_view kMetricLabelTarget = "grpc.target";
40
41 // A global registry of instruments(metrics). This API is designed to be used
42 // to register instruments (Counter, Histogram, and Gauge) as part of program
43 // startup, before the execution of the main function (during dynamic
44 // initialization time). Using this API after the main function begins may
45 // result into missing instruments. This API is thread-unsafe.
46 //
47 // The registration of instruments is done through the templated
48 // RegistrationBuilder API and gets back a handle with an opaque type. At
49 // runtime, the handle should be used with the StatsPluginGroup API to record
50 // metrics for the instruments.
51 //
52 // At dynamic initialization time:
53 // const auto kMetricHandle =
54 // GlobalInstrumentsRegistry::RegisterUInt64Counter(
55 // "name",
56 // "description",
57 // "unit", /*enable_by_default=*/false)
58 // .Labels(kLabel1, kLabel2, kLabel3)
59 // .OptionalLabels(kOptionalLabel1, kOptionalLabel2)
60 // .Build();
61 //
62 // At runtime time:
63 // stats_plugin_group.AddCounter(kMetricHandle, 1,
64 // {"label_value_1", "label_value_2", "label_value_3"},
65 // {"optional_label_value_1", "optional_label_value_2"});
66 //
67 class GlobalInstrumentsRegistry {
68 public:
69 enum class ValueType {
70 kUndefined,
71 kInt64,
72 kUInt64,
73 kDouble,
74 };
75 enum class InstrumentType {
76 kUndefined,
77 kCounter,
78 kHistogram,
79 kCallbackGauge,
80 };
81 using InstrumentID = uint32_t;
82 struct GlobalInstrumentDescriptor {
83 ValueType value_type;
84 InstrumentType instrument_type;
85 InstrumentID index;
86 bool enable_by_default;
87 absl::string_view name;
88 absl::string_view description;
89 absl::string_view unit;
90 std::vector<absl::string_view> label_keys;
91 std::vector<absl::string_view> optional_label_keys;
92 };
93 struct GlobalInstrumentHandle {
94 // This is the index for the corresponding registered instrument that
95 // StatsPlugins can use to uniquely identify an instrument in the current
96 // process. Though this is not guaranteed to be stable between different
97 // runs or between different versions.
98 InstrumentID index;
99 };
100
101 template <ValueType V, InstrumentType I, size_t M, size_t N>
102 struct TypedGlobalInstrumentHandle : public GlobalInstrumentHandle {};
103
104 template <ValueType V, InstrumentType I, std::size_t M, std::size_t N>
105 class RegistrationBuilder {
106 public:
107 template <typename... Args>
Labels(Args &&...args)108 RegistrationBuilder<V, I, sizeof...(Args), N> Labels(Args&&... args) {
109 return RegistrationBuilder<V, I, sizeof...(Args), N>(
110 name_, description_, unit_, enable_by_default_,
111 std::array<absl::string_view, sizeof...(Args)>({args...}),
112 optional_label_keys_);
113 }
114
115 template <typename... Args>
OptionalLabels(Args &&...args)116 RegistrationBuilder<V, I, M, sizeof...(Args)> OptionalLabels(
117 Args&&... args) {
118 return RegistrationBuilder<V, I, M, sizeof...(Args)>(
119 name_, description_, unit_, enable_by_default_, label_keys_,
120 std::array<absl::string_view, sizeof...(Args)>({args...}));
121 }
122
Build()123 TypedGlobalInstrumentHandle<V, I, M, N> Build() {
124 TypedGlobalInstrumentHandle<V, I, M, N> handle;
125 handle.index = RegisterInstrument(V, I, name_, description_, unit_,
126 enable_by_default_, label_keys_,
127 optional_label_keys_);
128 return handle;
129 }
130
131 private:
132 friend class GlobalInstrumentsRegistry;
133
RegistrationBuilder(absl::string_view name,absl::string_view description,absl::string_view unit,bool enable_by_default)134 RegistrationBuilder(absl::string_view name, absl::string_view description,
135 absl::string_view unit, bool enable_by_default)
136 : name_(name),
137 description_(description),
138 unit_(unit),
139 enable_by_default_(enable_by_default) {}
140
RegistrationBuilder(absl::string_view name,absl::string_view description,absl::string_view unit,bool enable_by_default,std::array<absl::string_view,M> label_keys,std::array<absl::string_view,N> optional_label_keys)141 RegistrationBuilder(absl::string_view name, absl::string_view description,
142 absl::string_view unit, bool enable_by_default,
143 std::array<absl::string_view, M> label_keys,
144 std::array<absl::string_view, N> optional_label_keys)
145 : name_(name),
146 description_(description),
147 unit_(unit),
148 enable_by_default_(enable_by_default),
149 label_keys_(std::move(label_keys)),
150 optional_label_keys_(std::move(optional_label_keys)) {}
151
152 absl::string_view name_;
153 absl::string_view description_;
154 absl::string_view unit_;
155 bool enable_by_default_;
156 std::array<absl::string_view, M> label_keys_;
157 std::array<absl::string_view, N> optional_label_keys_;
158 };
159
160 // Creates instrument in the GlobalInstrumentsRegistry.
161 static RegistrationBuilder<ValueType::kUInt64, InstrumentType::kCounter, 0, 0>
RegisterUInt64Counter(absl::string_view name,absl::string_view description,absl::string_view unit,bool enable_by_default)162 RegisterUInt64Counter(absl::string_view name, absl::string_view description,
163 absl::string_view unit, bool enable_by_default) {
164 return RegistrationBuilder<ValueType::kUInt64, InstrumentType::kCounter, 0,
165 0>(name, description, unit, enable_by_default);
166 }
167 static RegistrationBuilder<ValueType::kDouble, InstrumentType::kCounter, 0, 0>
RegisterDoubleCounter(absl::string_view name,absl::string_view description,absl::string_view unit,bool enable_by_default)168 RegisterDoubleCounter(absl::string_view name, absl::string_view description,
169 absl::string_view unit, bool enable_by_default) {
170 return RegistrationBuilder<ValueType::kDouble, InstrumentType::kCounter, 0,
171 0>(name, description, unit, enable_by_default);
172 }
173 static RegistrationBuilder<ValueType::kUInt64, InstrumentType::kHistogram, 0,
174 0>
RegisterUInt64Histogram(absl::string_view name,absl::string_view description,absl::string_view unit,bool enable_by_default)175 RegisterUInt64Histogram(absl::string_view name, absl::string_view description,
176 absl::string_view unit, bool enable_by_default) {
177 return RegistrationBuilder<ValueType::kUInt64, InstrumentType::kHistogram,
178 0, 0>(name, description, unit,
179 enable_by_default);
180 }
181 static RegistrationBuilder<ValueType::kDouble, InstrumentType::kHistogram, 0,
182 0>
RegisterDoubleHistogram(absl::string_view name,absl::string_view description,absl::string_view unit,bool enable_by_default)183 RegisterDoubleHistogram(absl::string_view name, absl::string_view description,
184 absl::string_view unit, bool enable_by_default) {
185 return RegistrationBuilder<ValueType::kDouble, InstrumentType::kHistogram,
186 0, 0>(name, description, unit,
187 enable_by_default);
188 }
189 static RegistrationBuilder<ValueType::kInt64, InstrumentType::kCallbackGauge,
190 0, 0>
RegisterCallbackInt64Gauge(absl::string_view name,absl::string_view description,absl::string_view unit,bool enable_by_default)191 RegisterCallbackInt64Gauge(absl::string_view name,
192 absl::string_view description,
193 absl::string_view unit, bool enable_by_default) {
194 return RegistrationBuilder<ValueType::kInt64,
195 InstrumentType::kCallbackGauge, 0, 0>(
196 name, description, unit, enable_by_default);
197 }
198 static RegistrationBuilder<ValueType::kDouble, InstrumentType::kCallbackGauge,
199 0, 0>
RegisterCallbackDoubleGauge(absl::string_view name,absl::string_view description,absl::string_view unit,bool enable_by_default)200 RegisterCallbackDoubleGauge(absl::string_view name,
201 absl::string_view description,
202 absl::string_view unit, bool enable_by_default) {
203 return RegistrationBuilder<ValueType::kDouble,
204 InstrumentType::kCallbackGauge, 0, 0>(
205 name, description, unit, enable_by_default);
206 }
207
208 static void ForEach(
209 absl::FunctionRef<void(const GlobalInstrumentDescriptor&)> f);
210 static const GlobalInstrumentDescriptor& GetInstrumentDescriptor(
211 GlobalInstrumentHandle handle);
212 static absl::optional<GlobalInstrumentsRegistry::GlobalInstrumentHandle>
213 FindInstrumentByName(absl::string_view name);
214
215 private:
216 friend class GlobalInstrumentsRegistryTestPeer;
217
218 GlobalInstrumentsRegistry() = delete;
219
220 static std::vector<GlobalInstrumentsRegistry::GlobalInstrumentDescriptor>&
221 GetInstrumentList();
222 static InstrumentID RegisterInstrument(
223 ValueType value_type, InstrumentType instrument_type,
224 absl::string_view name, absl::string_view description,
225 absl::string_view unit, bool enable_by_default,
226 absl::Span<const absl::string_view> label_keys,
227 absl::Span<const absl::string_view> optional_label_keys);
228 };
229
230 // An interface for implementing callback-style metrics.
231 // To be implemented by stats plugins.
232 class CallbackMetricReporter {
233 public:
234 virtual ~CallbackMetricReporter() = default;
235
236 template <std::size_t M, std::size_t N>
Report(GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<GlobalInstrumentsRegistry::ValueType::kInt64,GlobalInstrumentsRegistry::InstrumentType::kCallbackGauge,M,N> handle,int64_t value,std::array<absl::string_view,M> label_values,std::array<absl::string_view,N> optional_values)237 void Report(
238 GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<
239 GlobalInstrumentsRegistry::ValueType::kInt64,
240 GlobalInstrumentsRegistry::InstrumentType::kCallbackGauge, M, N>
241 handle,
242 int64_t value, std::array<absl::string_view, M> label_values,
243 std::array<absl::string_view, N> optional_values) {
244 ReportInt64(handle, value, label_values, optional_values);
245 }
246 template <std::size_t M, std::size_t N>
Report(GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<GlobalInstrumentsRegistry::ValueType::kDouble,GlobalInstrumentsRegistry::InstrumentType::kCallbackGauge,M,N> handle,double value,std::array<absl::string_view,M> label_values,std::array<absl::string_view,N> optional_values)247 void Report(
248 GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<
249 GlobalInstrumentsRegistry::ValueType::kDouble,
250 GlobalInstrumentsRegistry::InstrumentType::kCallbackGauge, M, N>
251 handle,
252 double value, std::array<absl::string_view, M> label_values,
253 std::array<absl::string_view, N> optional_values) {
254 ReportDouble(handle, value, label_values, optional_values);
255 }
256
257 private:
258 virtual void ReportInt64(
259 GlobalInstrumentsRegistry::GlobalInstrumentHandle handle, int64_t value,
260 absl::Span<const absl::string_view> label_values,
261 absl::Span<const absl::string_view> optional_values) = 0;
262 virtual void ReportDouble(
263 GlobalInstrumentsRegistry::GlobalInstrumentHandle handle, double value,
264 absl::Span<const absl::string_view> label_values,
265 absl::Span<const absl::string_view> optional_values) = 0;
266 };
267
268 class RegisteredMetricCallback;
269
270 // The StatsPlugin interface.
271 class StatsPlugin {
272 public:
273 // A general-purpose way for stats plugin to store per-channel or per-server
274 // state.
275 class ScopeConfig {
276 public:
277 virtual ~ScopeConfig() = default;
278 };
279
280 virtual ~StatsPlugin() = default;
281
282 // Whether this stats plugin is enabled for the channel specified by \a scope.
283 // Returns true and a channel-specific ScopeConfig which may then be used to
284 // configure the ClientCallTracer in GetClientCallTracer().
285 virtual std::pair<bool, std::shared_ptr<ScopeConfig>> IsEnabledForChannel(
286 const experimental::StatsPluginChannelScope& scope) const = 0;
287 // Whether this stats plugin is enabled for the server specified by \a args.
288 // Returns true and a server-specific ScopeConfig which may then be used to
289 // configure the ServerCallTracer in GetServerCallTracer().
290 virtual std::pair<bool, std::shared_ptr<ScopeConfig>> IsEnabledForServer(
291 const ChannelArgs& args) const = 0;
292 // Gets a scope config for the client channel specified by \a scope. Note that
293 // the stats plugin should have been enabled for the channel.
294 virtual std::shared_ptr<StatsPlugin::ScopeConfig> GetChannelScopeConfig(
295 const experimental::StatsPluginChannelScope& scope) const = 0;
296 // Gets a scope config for the server specified by \a args. Note that the
297 // stats plugin should have been enabled for the server.
298 virtual std::shared_ptr<StatsPlugin::ScopeConfig> GetServerScopeConfig(
299 const ChannelArgs& args) const = 0;
300
301 // Adds \a value to the uint64 counter specified by \a handle. \a label_values
302 // and \a optional_label_values specify attributes that are associated with
303 // this measurement and must match with their corresponding keys in
304 // GlobalInstrumentsRegistry::RegisterUInt64Counter().
305 virtual void AddCounter(
306 GlobalInstrumentsRegistry::GlobalInstrumentHandle handle, uint64_t value,
307 absl::Span<const absl::string_view> label_values,
308 absl::Span<const absl::string_view> optional_label_values) = 0;
309 // Adds \a value to the double counter specified by \a handle. \a label_values
310 // and \a optional_label_values specify attributes that are associated with
311 // this measurement and must match with their corresponding keys in
312 // GlobalInstrumentsRegistry::RegisterDoubleCounter().
313 virtual void AddCounter(
314 GlobalInstrumentsRegistry::GlobalInstrumentHandle handle, double value,
315 absl::Span<const absl::string_view> label_values,
316 absl::Span<const absl::string_view> optional_label_values) = 0;
317 // Records a uint64 \a value to the histogram specified by \a handle. \a
318 // label_values and \a optional_label_values specify attributes that are
319 // associated with this measurement and must match with their corresponding
320 // keys in GlobalInstrumentsRegistry::RegisterUInt64Histogram().
321 virtual void RecordHistogram(
322 GlobalInstrumentsRegistry::GlobalInstrumentHandle handle, uint64_t value,
323 absl::Span<const absl::string_view> label_values,
324 absl::Span<const absl::string_view> optional_label_values) = 0;
325 // Records a double \a value to the histogram specified by \a handle. \a
326 // label_values and \a optional_label_values specify attributes that are
327 // associated with this measurement and must match with their corresponding
328 // keys in GlobalInstrumentsRegistry::RegisterDoubleHistogram().
329 virtual void RecordHistogram(
330 GlobalInstrumentsRegistry::GlobalInstrumentHandle handle, double value,
331 absl::Span<const absl::string_view> label_values,
332 absl::Span<const absl::string_view> optional_label_values) = 0;
333 // Adds a callback to be invoked when the stats plugin wants to
334 // populate the corresponding metrics (see callback->metrics() for list).
335 virtual void AddCallback(RegisteredMetricCallback* callback) = 0;
336 // Removes a callback previously added via AddCallback(). The stats
337 // plugin may not use the callback after this method returns.
338 virtual void RemoveCallback(RegisteredMetricCallback* callback) = 0;
339 // Returns true if instrument \a handle is enabled.
340 virtual bool IsInstrumentEnabled(
341 GlobalInstrumentsRegistry::GlobalInstrumentHandle handle) const = 0;
342
343 // Gets a ClientCallTracer associated with this stats plugin which can be used
344 // in a call.
345 virtual ClientCallTracer* GetClientCallTracer(
346 const Slice& path, bool registered_method,
347 std::shared_ptr<ScopeConfig> scope_config) = 0;
348 // Gets a ServerCallTracer associated with this stats plugin which can be used
349 // in a call.
350 virtual ServerCallTracer* GetServerCallTracer(
351 std::shared_ptr<ScopeConfig> scope_config) = 0;
352
353 // TODO(yijiem): This is an optimization for the StatsPlugin to create its own
354 // representation of the label_values and use it multiple times. We would
355 // change AddCounter and RecordHistogram to take RefCountedPtr<LabelValueSet>
356 // and also change the StatsPluginsGroup to support this.
357 // Use the StatsPlugin to get a representation of label values that can be
358 // saved for multiple uses later.
359 // virtual RefCountedPtr<LabelValueSet> MakeLabelValueSet(
360 // absl::Span<absl::string_view> label_values) = 0;
361 };
362
363 // A global registry of stats plugins. It has shared ownership to the registered
364 // stats plugins. This API is supposed to be used during runtime after the main
365 // function begins. This API is thread-safe.
366 class GlobalStatsPluginRegistry {
367 public:
368 // A stats plugin group object is how the code in gRPC normally interacts with
369 // stats plugins. They got a stats plugin group which contains all the stats
370 // plugins for a specific scope and all operations on the stats plugin group
371 // will be applied to all the stats plugins within the group.
372 class StatsPluginGroup {
373 public:
374 // Adds a stats plugin and a scope config (per-channel or per-server) to the
375 // group.
AddStatsPlugin(std::shared_ptr<StatsPlugin> plugin,std::shared_ptr<StatsPlugin::ScopeConfig> config)376 void AddStatsPlugin(std::shared_ptr<StatsPlugin> plugin,
377 std::shared_ptr<StatsPlugin::ScopeConfig> config) {
378 PluginState plugin_state;
379 plugin_state.plugin = std::move(plugin);
380 plugin_state.scope_config = std::move(config);
381 plugins_state_.push_back(std::move(plugin_state));
382 }
383 // Adds a counter in all stats plugins within the group. See the StatsPlugin
384 // interface for more documentation and valid types.
385 template <std::size_t M, std::size_t N>
AddCounter(GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<GlobalInstrumentsRegistry::ValueType::kUInt64,GlobalInstrumentsRegistry::InstrumentType::kCounter,M,N> handle,uint64_t value,std::array<absl::string_view,M> label_values,std::array<absl::string_view,N> optional_values)386 void AddCounter(
387 GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<
388 GlobalInstrumentsRegistry::ValueType::kUInt64,
389 GlobalInstrumentsRegistry::InstrumentType::kCounter, M, N>
390 handle,
391 uint64_t value, std::array<absl::string_view, M> label_values,
392 std::array<absl::string_view, N> optional_values) {
393 for (auto& state : plugins_state_) {
394 state.plugin->AddCounter(handle, value, label_values, optional_values);
395 }
396 }
397 template <std::size_t M, std::size_t N>
AddCounter(GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<GlobalInstrumentsRegistry::ValueType::kDouble,GlobalInstrumentsRegistry::InstrumentType::kCounter,M,N> handle,double value,std::array<absl::string_view,M> label_values,std::array<absl::string_view,N> optional_values)398 void AddCounter(
399 GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<
400 GlobalInstrumentsRegistry::ValueType::kDouble,
401 GlobalInstrumentsRegistry::InstrumentType::kCounter, M, N>
402 handle,
403 double value, std::array<absl::string_view, M> label_values,
404 std::array<absl::string_view, N> optional_values) {
405 for (auto& state : plugins_state_) {
406 state.plugin->AddCounter(handle, value, label_values, optional_values);
407 }
408 }
409 // Records a value to a histogram in all stats plugins within the group. See
410 // the StatsPlugin interface for more documentation and valid types.
411 template <std::size_t M, std::size_t N>
RecordHistogram(GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<GlobalInstrumentsRegistry::ValueType::kUInt64,GlobalInstrumentsRegistry::InstrumentType::kHistogram,M,N> handle,uint64_t value,std::array<absl::string_view,M> label_values,std::array<absl::string_view,N> optional_values)412 void RecordHistogram(
413 GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<
414 GlobalInstrumentsRegistry::ValueType::kUInt64,
415 GlobalInstrumentsRegistry::InstrumentType::kHistogram, M, N>
416 handle,
417 uint64_t value, std::array<absl::string_view, M> label_values,
418 std::array<absl::string_view, N> optional_values) {
419 for (auto& state : plugins_state_) {
420 state.plugin->RecordHistogram(handle, value, label_values,
421 optional_values);
422 }
423 }
424 template <std::size_t M, std::size_t N>
RecordHistogram(GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<GlobalInstrumentsRegistry::ValueType::kDouble,GlobalInstrumentsRegistry::InstrumentType::kHistogram,M,N> handle,double value,std::array<absl::string_view,M> label_values,std::array<absl::string_view,N> optional_values)425 void RecordHistogram(
426 GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<
427 GlobalInstrumentsRegistry::ValueType::kDouble,
428 GlobalInstrumentsRegistry::InstrumentType::kHistogram, M, N>
429 handle,
430 double value, std::array<absl::string_view, M> label_values,
431 std::array<absl::string_view, N> optional_values) {
432 for (auto& state : plugins_state_) {
433 state.plugin->RecordHistogram(handle, value, label_values,
434 optional_values);
435 }
436 }
437 // Returns true if any of the stats plugins in the group have enabled \a
438 // handle.
IsInstrumentEnabled(GlobalInstrumentsRegistry::GlobalInstrumentHandle handle)439 bool IsInstrumentEnabled(
440 GlobalInstrumentsRegistry::GlobalInstrumentHandle handle) const {
441 for (auto& state : plugins_state_) {
442 if (state.plugin->IsInstrumentEnabled(handle)) {
443 return true;
444 }
445 }
446 return false;
447 }
448
size()449 size_t size() const { return plugins_state_.size(); }
450
451 // Registers a callback to be used to populate callback metrics.
452 // The callback will update the specified metrics. The callback
453 // will be invoked no more often than min_interval. Multiple callbacks may
454 // be registered for the same metrics, as long as no two callbacks report
455 // data for the same set of labels in which case the behavior is undefined.
456 //
457 // The returned object is a handle that allows the caller to control
458 // the lifetime of the callback; when the returned object is
459 // destroyed, the callback is de-registered. The returned object
460 // must not outlive the StatsPluginGroup object that created it.
461 template <typename... Args>
462 GRPC_MUST_USE_RESULT std::unique_ptr<RegisteredMetricCallback>
463 RegisterCallback(absl::AnyInvocable<void(CallbackMetricReporter&)> callback,
464 Duration min_interval, Args... args);
465
466 // Adds all available client call tracers associated with the stats plugins
467 // within the group to \a call_context.
468 void AddClientCallTracers(const Slice& path, bool registered_method,
469 Arena* arena);
470 // Adds all available server call tracers associated with the stats plugins
471 // within the group to \a call_context.
472 void AddServerCallTracers(Arena* arena);
473
474 private:
475 friend class RegisteredMetricCallback;
476
477 struct PluginState {
478 std::shared_ptr<StatsPlugin::ScopeConfig> scope_config;
479 std::shared_ptr<StatsPlugin> plugin;
480 };
481
482 // C++17 has fold expression that may simplify this.
483 template <GlobalInstrumentsRegistry::ValueType V,
484 GlobalInstrumentsRegistry::InstrumentType I, size_t M, size_t N>
AssertIsCallbackGaugeHandle(GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<V,I,M,N>)485 static constexpr void AssertIsCallbackGaugeHandle(
486 GlobalInstrumentsRegistry::TypedGlobalInstrumentHandle<V, I, M, N>) {
487 static_assert(V == GlobalInstrumentsRegistry::ValueType::kInt64 ||
488 V == GlobalInstrumentsRegistry::ValueType::kDouble,
489 "ValueType must be kInt64 or kDouble");
490 static_assert(
491 I == GlobalInstrumentsRegistry::InstrumentType::kCallbackGauge,
492 "InstrumentType must be kCallbackGauge");
493 }
494 template <typename T, typename... Args>
AssertIsCallbackGaugeHandle(T t,Args &&...args)495 static constexpr void AssertIsCallbackGaugeHandle(T t, Args&&... args) {
496 AssertIsCallbackGaugeHandle(t);
497 AssertIsCallbackGaugeHandle(args...);
498 }
499
500 std::vector<PluginState> plugins_state_;
501 };
502
503 // Registers a stats plugin with the global stats plugin registry.
504 static void RegisterStatsPlugin(std::shared_ptr<StatsPlugin> plugin);
505
506 // The following functions can be invoked to get a StatsPluginGroup for
507 // a specified scope.
508 static StatsPluginGroup GetStatsPluginsForChannel(
509 const experimental::StatsPluginChannelScope& scope);
510 static StatsPluginGroup GetStatsPluginsForServer(const ChannelArgs& args);
511
512 private:
513 struct GlobalStatsPluginNode {
514 std::shared_ptr<StatsPlugin> plugin;
515 GlobalStatsPluginNode* next = nullptr;
516 };
517 friend class GlobalStatsPluginRegistryTestPeer;
518
519 GlobalStatsPluginRegistry() = default;
520
521 static std::atomic<GlobalStatsPluginNode*> plugins_;
522 };
523
524 // A metric callback that is registered with a stats plugin group.
525 class RegisteredMetricCallback {
526 public:
527 RegisteredMetricCallback(
528 GlobalStatsPluginRegistry::StatsPluginGroup& stats_plugin_group,
529 absl::AnyInvocable<void(CallbackMetricReporter&)> callback,
530 std::vector<GlobalInstrumentsRegistry::GlobalInstrumentHandle> metrics,
531 Duration min_interval);
532
533 ~RegisteredMetricCallback();
534
535 // Invokes the callback. The callback will report metric data via reporter.
Run(CallbackMetricReporter & reporter)536 void Run(CallbackMetricReporter& reporter) { callback_(reporter); }
537
538 // Returns the set of metrics that this callback will modify.
539 const std::vector<GlobalInstrumentsRegistry::GlobalInstrumentHandle>&
metrics()540 metrics() const {
541 return metrics_;
542 }
543
544 // Returns the minimum interval at which a stats plugin may invoke the
545 // callback.
min_interval()546 Duration min_interval() const { return min_interval_; }
547
548 private:
549 GlobalStatsPluginRegistry::StatsPluginGroup& stats_plugin_group_;
550 absl::AnyInvocable<void(CallbackMetricReporter&)> callback_;
551 std::vector<GlobalInstrumentsRegistry::GlobalInstrumentHandle> metrics_;
552 Duration min_interval_;
553 };
554
555 template <typename... Args>
556 inline std::unique_ptr<RegisteredMetricCallback>
RegisterCallback(absl::AnyInvocable<void (CallbackMetricReporter &)> callback,Duration min_interval,Args...args)557 GlobalStatsPluginRegistry::StatsPluginGroup::RegisterCallback(
558 absl::AnyInvocable<void(CallbackMetricReporter&)> callback,
559 Duration min_interval, Args... args) {
560 AssertIsCallbackGaugeHandle(args...);
561 return std::make_unique<RegisteredMetricCallback>(
562 *this, std::move(callback),
563 std::vector<GlobalInstrumentsRegistry::GlobalInstrumentHandle>{args...},
564 min_interval);
565 }
566
567 } // namespace grpc_core
568
569 #endif // GRPC_SRC_CORE_TELEMETRY_METRICS_H
570