• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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