xref: /aosp_15_r20/external/grpc-grpc/src/core/lib/channel/metrics.h (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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_LIB_CHANNEL_METRICS_H
16 #define GRPC_SRC_CORE_LIB_CHANNEL_METRICS_H
17 
18 #include <grpc/support/port_platform.h>
19 
20 #include <cstdint>
21 #include <memory>
22 #include <vector>
23 
24 #include "absl/container/flat_hash_map.h"
25 #include "absl/functional/any_invocable.h"
26 #include "absl/functional/function_ref.h"
27 #include "absl/strings/string_view.h"
28 #include "absl/types/span.h"
29 
30 #include <grpc/support/log.h>
31 #include <grpc/support/metrics.h>
32 
33 #include "src/core/lib/channel/call_tracer.h"
34 #include "src/core/lib/channel/channel_args.h"
35 #include "src/core/lib/channel/context.h"
36 #include "src/core/lib/gprpp/no_destruct.h"
37 #include "src/core/lib/gprpp/sync.h"
38 #include "src/core/lib/gprpp/time.h"
39 #include "src/core/lib/slice/slice.h"
40 
41 namespace grpc_core {
42 
43 constexpr absl::string_view kMetricLabelTarget = "grpc.target";
44 
45 // A global registry of instruments(metrics). This API is designed to be used
46 // to register instruments (Counter, Histogram, and Gauge) as part of program
47 // startup, before the execution of the main function (during dynamic
48 // initialization time). Using this API after the main function begins may
49 // result into missing instruments. This API is thread-unsafe.
50 class GlobalInstrumentsRegistry {
51  public:
52   enum class ValueType {
53     kUndefined,
54     kInt64,
55     kUInt64,
56     kDouble,
57   };
58   enum class InstrumentType {
59     kUndefined,
60     kCounter,
61     kHistogram,
62     kGauge,
63     kCallbackGauge,
64   };
65   using InstrumentID = uint32_t;
66   struct GlobalInstrumentDescriptor {
67     ValueType value_type;
68     InstrumentType instrument_type;
69     InstrumentID index;
70     bool enable_by_default;
71     absl::string_view name;
72     absl::string_view description;
73     absl::string_view unit;
74     std::vector<absl::string_view> label_keys;
75     std::vector<absl::string_view> optional_label_keys;
76   };
77   struct GlobalInstrumentHandle {
78     // This is the index for the corresponding registered instrument that
79     // StatsPlugins can use to uniquely identify an instrument in the current
80     // process. Though this is not guaranteed to be stable between different
81     // runs or between different versions.
82     InstrumentID index;
83   };
84   struct GlobalUInt64CounterHandle : public GlobalInstrumentHandle {};
85   struct GlobalDoubleCounterHandle : public GlobalInstrumentHandle {};
86   struct GlobalUInt64HistogramHandle : public GlobalInstrumentHandle {};
87   struct GlobalDoubleHistogramHandle : public GlobalInstrumentHandle {};
88   struct GlobalInt64GaugeHandle : public GlobalInstrumentHandle {};
89   struct GlobalDoubleGaugeHandle : public GlobalInstrumentHandle {};
90   struct GlobalCallbackInt64GaugeHandle : public GlobalInstrumentHandle {};
91   struct GlobalCallbackDoubleGaugeHandle : public GlobalInstrumentHandle {};
92   using GlobalCallbackHandle = absl::variant<GlobalCallbackInt64GaugeHandle,
93                                              GlobalCallbackDoubleGaugeHandle>;
94 
95   // Creates instrument in the GlobalInstrumentsRegistry.
96   static GlobalUInt64CounterHandle RegisterUInt64Counter(
97       absl::string_view name, absl::string_view description,
98       absl::string_view unit, absl::Span<const absl::string_view> label_keys,
99       absl::Span<const absl::string_view> optional_label_keys,
100       bool enable_by_default);
101   static GlobalDoubleCounterHandle RegisterDoubleCounter(
102       absl::string_view name, absl::string_view description,
103       absl::string_view unit, absl::Span<const absl::string_view> label_keys,
104       absl::Span<const absl::string_view> optional_label_keys,
105       bool enable_by_default);
106   static GlobalUInt64HistogramHandle RegisterUInt64Histogram(
107       absl::string_view name, absl::string_view description,
108       absl::string_view unit, absl::Span<const absl::string_view> label_keys,
109       absl::Span<const absl::string_view> optional_label_keys,
110       bool enable_by_default);
111   static GlobalDoubleHistogramHandle RegisterDoubleHistogram(
112       absl::string_view name, absl::string_view description,
113       absl::string_view unit, absl::Span<const absl::string_view> label_keys,
114       absl::Span<const absl::string_view> optional_label_keys,
115       bool enable_by_default);
116   static GlobalInt64GaugeHandle RegisterInt64Gauge(
117       absl::string_view name, absl::string_view description,
118       absl::string_view unit, absl::Span<const absl::string_view> label_keys,
119       absl::Span<const absl::string_view> optional_label_keys,
120       bool enable_by_default);
121   static GlobalDoubleGaugeHandle RegisterDoubleGauge(
122       absl::string_view name, absl::string_view description,
123       absl::string_view unit, absl::Span<const absl::string_view> label_keys,
124       absl::Span<const absl::string_view> optional_label_keys,
125       bool enable_by_default);
126   static GlobalCallbackInt64GaugeHandle RegisterCallbackInt64Gauge(
127       absl::string_view name, absl::string_view description,
128       absl::string_view unit, absl::Span<const absl::string_view> label_keys,
129       absl::Span<const absl::string_view> optional_label_keys,
130       bool enable_by_default);
131   static GlobalCallbackDoubleGaugeHandle RegisterCallbackDoubleGauge(
132       absl::string_view name, absl::string_view description,
133       absl::string_view unit, absl::Span<const absl::string_view> label_keys,
134       absl::Span<const absl::string_view> optional_label_keys,
135       bool enable_by_default);
136 
137   static void ForEach(
138       absl::FunctionRef<void(const GlobalInstrumentDescriptor&)> f);
139   static const GlobalInstrumentDescriptor& GetInstrumentDescriptor(
140       GlobalInstrumentHandle handle);
141 
142  private:
143   friend class GlobalInstrumentsRegistryTestPeer;
144 
145   GlobalInstrumentsRegistry() = delete;
146 
147   static std::vector<GlobalInstrumentsRegistry::GlobalInstrumentDescriptor>&
148   GetInstrumentList();
149 };
150 
151 // An interface for implementing callback-style metrics.
152 // To be implemented by stats plugins.
153 class CallbackMetricReporter {
154  public:
155   virtual ~CallbackMetricReporter() = default;
156 
157   virtual void Report(
158       GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle handle,
159       int64_t value, absl::Span<const absl::string_view> label_values,
160       absl::Span<const absl::string_view> optional_values) = 0;
161   virtual void Report(
162       GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle handle,
163       double value, absl::Span<const absl::string_view> label_values,
164       absl::Span<const absl::string_view> optional_values) = 0;
165 };
166 
167 class RegisteredMetricCallback;
168 
169 // The StatsPlugin interface.
170 class StatsPlugin {
171  public:
172   // A general-purpose way for stats plugin to store per-channel or per-server
173   // state.
174   class ScopeConfig {
175    public:
176     virtual ~ScopeConfig() = default;
177   };
178 
179   virtual ~StatsPlugin() = default;
180 
181   // Whether this stats plugin is enabled for the channel specified by \a scope.
182   // Returns true and a channel-specific ScopeConfig which may then be used to
183   // configure the ClientCallTracer in GetClientCallTracer().
184   virtual std::pair<bool, std::shared_ptr<ScopeConfig>> IsEnabledForChannel(
185       const experimental::StatsPluginChannelScope& scope) const = 0;
186   // Whether this stats plugin is enabled for the server specified by \a args.
187   // Returns true and a server-specific ScopeConfig which may then be used to
188   // configure the ServerCallTracer in GetServerCallTracer().
189   virtual std::pair<bool, std::shared_ptr<ScopeConfig>> IsEnabledForServer(
190       const ChannelArgs& args) const = 0;
191 
192   // Adds \a value to the uint64 counter specified by \a handle. \a label_values
193   // and \a optional_label_values specify attributes that are associated with
194   // this measurement and must match with their corresponding keys in
195   // GlobalInstrumentsRegistry::RegisterUInt64Counter().
196   virtual void AddCounter(
197       GlobalInstrumentsRegistry::GlobalUInt64CounterHandle handle,
198       uint64_t value, absl::Span<const absl::string_view> label_values,
199       absl::Span<const absl::string_view> optional_label_values) = 0;
200   // Adds \a value to the double counter specified by \a handle. \a label_values
201   // and \a optional_label_values specify attributes that are associated with
202   // this measurement and must match with their corresponding keys in
203   // GlobalInstrumentsRegistry::RegisterDoubleCounter().
204   virtual void AddCounter(
205       GlobalInstrumentsRegistry::GlobalDoubleCounterHandle handle, double value,
206       absl::Span<const absl::string_view> label_values,
207       absl::Span<const absl::string_view> optional_label_values) = 0;
208   // Records a uint64 \a value to the histogram specified by \a handle. \a
209   // label_values and \a optional_label_values specify attributes that are
210   // associated with this measurement and must match with their corresponding
211   // keys in GlobalInstrumentsRegistry::RegisterUInt64Histogram().
212   virtual void RecordHistogram(
213       GlobalInstrumentsRegistry::GlobalUInt64HistogramHandle handle,
214       uint64_t value, absl::Span<const absl::string_view> label_values,
215       absl::Span<const absl::string_view> optional_label_values) = 0;
216   // Records a double \a value to the histogram specified by \a handle. \a
217   // label_values and \a optional_label_values specify attributes that are
218   // associated with this measurement and must match with their corresponding
219   // keys in GlobalInstrumentsRegistry::RegisterDoubleHistogram().
220   virtual void RecordHistogram(
221       GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle handle,
222       double value, absl::Span<const absl::string_view> label_values,
223       absl::Span<const absl::string_view> optional_label_values) = 0;
224   // Sets an int64 \a value to the gauge specifed by \a handle. \a
225   // label_values and \a optional_label_values specify attributes that are
226   // associated with this measurement and must match with their corresponding
227   // keys in GlobalInstrumentsRegistry::RegisterInt64Gauge().
228   virtual void SetGauge(
229       GlobalInstrumentsRegistry::GlobalInt64GaugeHandle handle, int64_t value,
230       absl::Span<const absl::string_view> label_values,
231       absl::Span<const absl::string_view> optional_label_values) = 0;
232   // Sets a double \a value to the gauge specifed by \a handle. \a
233   // label_values and \a optional_label_values specify attributes that are
234   // associated with this measurement and must match with their corresponding
235   // keys in GlobalInstrumentsRegistry::RegisterDoubleGauge().
236   virtual void SetGauge(
237       GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle handle, double value,
238       absl::Span<const absl::string_view> label_values,
239       absl::Span<const absl::string_view> optional_label_values) = 0;
240   // Adds a callback to be invoked when the stats plugin wants to
241   // populate the corresponding metrics (see callback->metrics() for list).
242   virtual void AddCallback(RegisteredMetricCallback* callback) = 0;
243   // Removes a callback previously added via AddCallback().  The stats
244   // plugin may not use the callback after this method returns.
245   virtual void RemoveCallback(RegisteredMetricCallback* callback) = 0;
246 
247   // Gets a ClientCallTracer associated with this stats plugin which can be used
248   // in a call.
249   virtual ClientCallTracer* GetClientCallTracer(
250       const Slice& path, bool registered_method,
251       std::shared_ptr<ScopeConfig> scope_config) = 0;
252   // Gets a ServerCallTracer associated with this stats plugin which can be used
253   // in a call.
254   virtual ServerCallTracer* GetServerCallTracer(
255       std::shared_ptr<ScopeConfig> scope_config) = 0;
256 
257   // TODO(yijiem): This is an optimization for the StatsPlugin to create its own
258   // representation of the label_values and use it multiple times. We would
259   // change AddCounter and RecordHistogram to take RefCountedPtr<LabelValueSet>
260   // and also change the StatsPluginsGroup to support this.
261   // Use the StatsPlugin to get a representation of label values that can be
262   // saved for multiple uses later.
263   // virtual RefCountedPtr<LabelValueSet> MakeLabelValueSet(
264   //     absl::Span<absl::string_view> label_values) = 0;
265 };
266 
267 // A global registry of stats plugins. It has shared ownership to the registered
268 // stats plugins. This API is supposed to be used during runtime after the main
269 // function begins. This API is thread-safe.
270 class GlobalStatsPluginRegistry {
271  public:
272   // A stats plugin group object is how the code in gRPC normally interacts with
273   // stats plugins. They got a stats plugin group which contains all the stats
274   // plugins for a specific scope and all operations on the stats plugin group
275   // will be applied to all the stats plugins within the group.
276   class StatsPluginGroup {
277    public:
278     // Adds a stats plugin and a scope config (per-channel or per-server) to the
279     // group.
AddStatsPlugin(std::shared_ptr<StatsPlugin> plugin,std::shared_ptr<StatsPlugin::ScopeConfig> config)280     void AddStatsPlugin(std::shared_ptr<StatsPlugin> plugin,
281                         std::shared_ptr<StatsPlugin::ScopeConfig> config) {
282       PluginState plugin_state;
283       plugin_state.plugin = std::move(plugin);
284       plugin_state.scope_config = std::move(config);
285       plugins_state_.push_back(std::move(plugin_state));
286     }
287     // Adds a counter in all stats plugins within the group. See the StatsPlugin
288     // interface for more documentation and valid types.
289     template <class HandleType, class ValueType>
AddCounter(HandleType handle,ValueType value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)290     void AddCounter(HandleType handle, ValueType value,
291                     absl::Span<const absl::string_view> label_values,
292                     absl::Span<const absl::string_view> optional_values) {
293       for (auto& state : plugins_state_) {
294         state.plugin->AddCounter(handle, value, label_values, optional_values);
295       }
296     }
297     // Records a value to a histogram in all stats plugins within the group. See
298     // the StatsPlugin interface for more documentation and valid types.
299     template <class HandleType, class ValueType>
RecordHistogram(HandleType handle,ValueType value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)300     void RecordHistogram(HandleType handle, ValueType value,
301                          absl::Span<const absl::string_view> label_values,
302                          absl::Span<const absl::string_view> optional_values) {
303       for (auto& state : plugins_state_) {
304         state.plugin->RecordHistogram(handle, value, label_values,
305                                       optional_values);
306       }
307     }
308     // Sets a value to a gauge in all stats plugins within the group. See the
309     // StatsPlugin interface for more documentation and valid types.
310     template <class HandleType, class ValueType>
SetGauge(HandleType handle,ValueType value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)311     void SetGauge(HandleType handle, ValueType value,
312                   absl::Span<const absl::string_view> label_values,
313                   absl::Span<const absl::string_view> optional_values) {
314       for (auto& state : plugins_state_) {
315         state.plugin->SetGauge(handle, value, label_values, optional_values);
316       }
317     }
318 
319     // Registers a callback to be used to populate callback metrics.
320     // The callback will update the specified metrics.  The callback
321     // will be invoked no more often than min_interval.  Multiple callbacks may
322     // be registered for the same metrics, as long as no two callbacks report
323     // data for the same set of labels in which case the behavior is undefined.
324     //
325     // The returned object is a handle that allows the caller to control
326     // the lifetime of the callback; when the returned object is
327     // destroyed, the callback is de-registered.  The returned object
328     // must not outlive the StatsPluginGroup object that created it.
329     GRPC_MUST_USE_RESULT std::unique_ptr<RegisteredMetricCallback>
330     RegisterCallback(
331         absl::AnyInvocable<void(CallbackMetricReporter&)> callback,
332         std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle> metrics,
333         Duration min_interval = Duration::Seconds(5));
334 
335     // Adds all available client call tracers associated with the stats plugins
336     // within the group to \a call_context.
337     void AddClientCallTracers(const Slice& path, bool registered_method,
338                               grpc_call_context_element* call_context);
339     // Adds all available server call tracers associated with the stats plugins
340     // within the group to \a call_context.
341     void AddServerCallTracers(grpc_call_context_element* call_context);
342 
343    private:
344     friend class RegisteredMetricCallback;
345 
346     struct PluginState {
347       std::shared_ptr<StatsPlugin::ScopeConfig> scope_config;
348       std::shared_ptr<StatsPlugin> plugin;
349     };
350 
351     std::vector<PluginState> plugins_state_;
352   };
353 
354   // Registers a stats plugin with the global stats plugin registry.
355   static void RegisterStatsPlugin(std::shared_ptr<StatsPlugin> plugin);
356 
357   // The following functions can be invoked to get a StatsPluginGroup for
358   // a specified scope.
359   static StatsPluginGroup GetStatsPluginsForChannel(
360       const experimental::StatsPluginChannelScope& scope);
361   static StatsPluginGroup GetStatsPluginsForServer(const ChannelArgs& args);
362 
363  private:
364   friend class GlobalStatsPluginRegistryTestPeer;
365 
366   GlobalStatsPluginRegistry() = default;
367 
368   static NoDestruct<Mutex> mutex_;
369   static NoDestruct<std::vector<std::shared_ptr<StatsPlugin>>> plugins_
370       ABSL_GUARDED_BY(mutex_);
371 };
372 
373 // A metric callback that is registered with a stats plugin group.
374 class RegisteredMetricCallback {
375  public:
376   RegisteredMetricCallback(
377       GlobalStatsPluginRegistry::StatsPluginGroup& stats_plugin_group,
378       absl::AnyInvocable<void(CallbackMetricReporter&)> callback,
379       std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle> metrics,
380       Duration min_interval);
381 
382   ~RegisteredMetricCallback();
383 
384   // Invokes the callback.  The callback will report metric data via reporter.
Run(CallbackMetricReporter & reporter)385   void Run(CallbackMetricReporter& reporter) { callback_(reporter); }
386 
387   // Returns the set of metrics that this callback will modify.
metrics()388   const std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle>& metrics()
389       const {
390     return metrics_;
391   }
392 
393   // Returns the minimum interval at which a stats plugin may invoke the
394   // callback.
min_interval()395   Duration min_interval() const { return min_interval_; }
396 
397  private:
398   GlobalStatsPluginRegistry::StatsPluginGroup& stats_plugin_group_;
399   absl::AnyInvocable<void(CallbackMetricReporter&)> callback_;
400   std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle> metrics_;
401   Duration min_interval_;
402 };
403 
404 }  // namespace grpc_core
405 
406 #endif  // GRPC_SRC_CORE_LIB_CHANNEL_METRICS_H
407