xref: /aosp_15_r20/external/grpc-grpc/src/core/lib/channel/metrics.cc (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 #include <grpc/support/port_platform.h>
16 
17 #include "src/core/lib/channel/metrics.h"
18 
19 #include <memory>
20 
21 #include "src/core/lib/gprpp/crash.h"
22 
23 namespace grpc_core {
24 
25 // Uses the Construct-on-First-Use idiom to avoid the static initialization
26 // order fiasco.
27 std::vector<GlobalInstrumentsRegistry::GlobalInstrumentDescriptor>&
GetInstrumentList()28 GlobalInstrumentsRegistry::GetInstrumentList() {
29   static NoDestruct<
30       std::vector<GlobalInstrumentsRegistry::GlobalInstrumentDescriptor>>
31       instruments;
32   return *instruments;
33 }
34 
35 GlobalInstrumentsRegistry::GlobalUInt64CounterHandle
RegisterUInt64Counter(absl::string_view name,absl::string_view description,absl::string_view unit,absl::Span<const absl::string_view> label_keys,absl::Span<const absl::string_view> optional_label_keys,bool enable_by_default)36 GlobalInstrumentsRegistry::RegisterUInt64Counter(
37     absl::string_view name, absl::string_view description,
38     absl::string_view unit, absl::Span<const absl::string_view> label_keys,
39     absl::Span<const absl::string_view> optional_label_keys,
40     bool enable_by_default) {
41   auto& instruments = GetInstrumentList();
42   for (const auto& descriptor : instruments) {
43     if (descriptor.name == name) {
44       Crash(
45           absl::StrFormat("Metric name %s has already been registered.", name));
46     }
47   }
48   uint32_t index = instruments.size();
49   GPR_ASSERT(index < std::numeric_limits<uint32_t>::max());
50   GlobalInstrumentDescriptor descriptor;
51   descriptor.value_type = ValueType::kUInt64;
52   descriptor.instrument_type = InstrumentType::kCounter;
53   descriptor.index = index;
54   descriptor.enable_by_default = enable_by_default;
55   descriptor.name = name;
56   descriptor.description = description;
57   descriptor.unit = unit;
58   descriptor.label_keys = {label_keys.begin(), label_keys.end()};
59   descriptor.optional_label_keys = {optional_label_keys.begin(),
60                                     optional_label_keys.end()};
61   instruments.push_back(std::move(descriptor));
62   GlobalUInt64CounterHandle handle;
63   handle.index = index;
64   return handle;
65 }
66 
67 GlobalInstrumentsRegistry::GlobalDoubleCounterHandle
RegisterDoubleCounter(absl::string_view name,absl::string_view description,absl::string_view unit,absl::Span<const absl::string_view> label_keys,absl::Span<const absl::string_view> optional_label_keys,bool enable_by_default)68 GlobalInstrumentsRegistry::RegisterDoubleCounter(
69     absl::string_view name, absl::string_view description,
70     absl::string_view unit, absl::Span<const absl::string_view> label_keys,
71     absl::Span<const absl::string_view> optional_label_keys,
72     bool enable_by_default) {
73   auto& instruments = GetInstrumentList();
74   for (const auto& descriptor : instruments) {
75     if (descriptor.name == name) {
76       Crash(
77           absl::StrFormat("Metric name %s has already been registered.", name));
78     }
79   }
80   uint32_t index = instruments.size();
81   GPR_ASSERT(index < std::numeric_limits<uint32_t>::max());
82   GlobalInstrumentDescriptor descriptor;
83   descriptor.value_type = ValueType::kDouble;
84   descriptor.instrument_type = InstrumentType::kCounter;
85   descriptor.index = index;
86   descriptor.enable_by_default = enable_by_default;
87   descriptor.name = name;
88   descriptor.description = description;
89   descriptor.unit = unit;
90   descriptor.label_keys = {label_keys.begin(), label_keys.end()};
91   descriptor.optional_label_keys = {optional_label_keys.begin(),
92                                     optional_label_keys.end()};
93   instruments.push_back(std::move(descriptor));
94   GlobalDoubleCounterHandle handle;
95   handle.index = index;
96   return handle;
97 }
98 
99 GlobalInstrumentsRegistry::GlobalUInt64HistogramHandle
RegisterUInt64Histogram(absl::string_view name,absl::string_view description,absl::string_view unit,absl::Span<const absl::string_view> label_keys,absl::Span<const absl::string_view> optional_label_keys,bool enable_by_default)100 GlobalInstrumentsRegistry::RegisterUInt64Histogram(
101     absl::string_view name, absl::string_view description,
102     absl::string_view unit, absl::Span<const absl::string_view> label_keys,
103     absl::Span<const absl::string_view> optional_label_keys,
104     bool enable_by_default) {
105   auto& instruments = GetInstrumentList();
106   for (const auto& descriptor : instruments) {
107     if (descriptor.name == name) {
108       Crash(
109           absl::StrFormat("Metric name %s has already been registered.", name));
110     }
111   }
112   uint32_t index = instruments.size();
113   GPR_ASSERT(index < std::numeric_limits<uint32_t>::max());
114   GlobalInstrumentDescriptor descriptor;
115   descriptor.value_type = ValueType::kUInt64;
116   descriptor.instrument_type = InstrumentType::kHistogram;
117   descriptor.index = index;
118   descriptor.enable_by_default = enable_by_default;
119   descriptor.name = name;
120   descriptor.description = description;
121   descriptor.unit = unit;
122   descriptor.label_keys = {label_keys.begin(), label_keys.end()};
123   descriptor.optional_label_keys = {optional_label_keys.begin(),
124                                     optional_label_keys.end()};
125   instruments.push_back(std::move(descriptor));
126   GlobalUInt64HistogramHandle handle;
127   handle.index = index;
128   return handle;
129 }
130 
131 GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle
RegisterDoubleHistogram(absl::string_view name,absl::string_view description,absl::string_view unit,absl::Span<const absl::string_view> label_keys,absl::Span<const absl::string_view> optional_label_keys,bool enable_by_default)132 GlobalInstrumentsRegistry::RegisterDoubleHistogram(
133     absl::string_view name, absl::string_view description,
134     absl::string_view unit, absl::Span<const absl::string_view> label_keys,
135     absl::Span<const absl::string_view> optional_label_keys,
136     bool enable_by_default) {
137   auto& instruments = GetInstrumentList();
138   for (const auto& descriptor : instruments) {
139     if (descriptor.name == name) {
140       Crash(
141           absl::StrFormat("Metric name %s has already been registered.", name));
142     }
143   }
144   uint32_t index = instruments.size();
145   GPR_ASSERT(index < std::numeric_limits<uint32_t>::max());
146   GlobalInstrumentDescriptor descriptor;
147   descriptor.value_type = ValueType::kDouble;
148   descriptor.instrument_type = InstrumentType::kHistogram;
149   descriptor.index = index;
150   descriptor.enable_by_default = enable_by_default;
151   descriptor.name = name;
152   descriptor.description = description;
153   descriptor.unit = unit;
154   descriptor.label_keys = {label_keys.begin(), label_keys.end()};
155   descriptor.optional_label_keys = {optional_label_keys.begin(),
156                                     optional_label_keys.end()};
157   instruments.push_back(std::move(descriptor));
158   GlobalDoubleHistogramHandle handle;
159   handle.index = index;
160   return handle;
161 }
162 
163 GlobalInstrumentsRegistry::GlobalInt64GaugeHandle
RegisterInt64Gauge(absl::string_view name,absl::string_view description,absl::string_view unit,absl::Span<const absl::string_view> label_keys,absl::Span<const absl::string_view> optional_label_keys,bool enable_by_default)164 GlobalInstrumentsRegistry::RegisterInt64Gauge(
165     absl::string_view name, absl::string_view description,
166     absl::string_view unit, absl::Span<const absl::string_view> label_keys,
167     absl::Span<const absl::string_view> optional_label_keys,
168     bool enable_by_default) {
169   auto& instruments = GetInstrumentList();
170   for (const auto& descriptor : instruments) {
171     if (descriptor.name == name) {
172       Crash(
173           absl::StrFormat("Metric name %s has already been registered.", name));
174     }
175   }
176   uint32_t index = instruments.size();
177   GPR_ASSERT(index < std::numeric_limits<uint32_t>::max());
178   GlobalInstrumentDescriptor descriptor;
179   descriptor.value_type = ValueType::kInt64;
180   descriptor.instrument_type = InstrumentType::kGauge;
181   descriptor.index = index;
182   descriptor.enable_by_default = enable_by_default;
183   descriptor.name = name;
184   descriptor.description = description;
185   descriptor.unit = unit;
186   descriptor.label_keys = {label_keys.begin(), label_keys.end()};
187   descriptor.optional_label_keys = {optional_label_keys.begin(),
188                                     optional_label_keys.end()};
189   instruments.push_back(std::move(descriptor));
190   GlobalInt64GaugeHandle handle;
191   handle.index = index;
192   return handle;
193 }
194 
195 GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle
RegisterDoubleGauge(absl::string_view name,absl::string_view description,absl::string_view unit,absl::Span<const absl::string_view> label_keys,absl::Span<const absl::string_view> optional_label_keys,bool enable_by_default)196 GlobalInstrumentsRegistry::RegisterDoubleGauge(
197     absl::string_view name, absl::string_view description,
198     absl::string_view unit, absl::Span<const absl::string_view> label_keys,
199     absl::Span<const absl::string_view> optional_label_keys,
200     bool enable_by_default) {
201   auto& instruments = GetInstrumentList();
202   for (const auto& descriptor : instruments) {
203     if (descriptor.name == name) {
204       Crash(
205           absl::StrFormat("Metric name %s has already been registered.", name));
206     }
207   }
208   uint32_t index = instruments.size();
209   GPR_ASSERT(index < std::numeric_limits<uint32_t>::max());
210   GlobalInstrumentDescriptor descriptor;
211   descriptor.value_type = ValueType::kDouble;
212   descriptor.instrument_type = InstrumentType::kGauge;
213   descriptor.index = index;
214   descriptor.enable_by_default = enable_by_default;
215   descriptor.name = name;
216   descriptor.description = description;
217   descriptor.unit = unit;
218   descriptor.label_keys = {label_keys.begin(), label_keys.end()};
219   descriptor.optional_label_keys = {optional_label_keys.begin(),
220                                     optional_label_keys.end()};
221   instruments.push_back(std::move(descriptor));
222   GlobalDoubleGaugeHandle handle;
223   handle.index = index;
224   return handle;
225 }
226 
227 GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle
RegisterCallbackInt64Gauge(absl::string_view name,absl::string_view description,absl::string_view unit,absl::Span<const absl::string_view> label_keys,absl::Span<const absl::string_view> optional_label_keys,bool enable_by_default)228 GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
229     absl::string_view name, absl::string_view description,
230     absl::string_view unit, absl::Span<const absl::string_view> label_keys,
231     absl::Span<const absl::string_view> optional_label_keys,
232     bool enable_by_default) {
233   auto& instruments = GetInstrumentList();
234   for (const auto& descriptor : instruments) {
235     if (descriptor.name == name) {
236       Crash(
237           absl::StrFormat("Metric name %s has already been registered.", name));
238     }
239   }
240   uint32_t index = instruments.size();
241   GPR_ASSERT(index < std::numeric_limits<uint32_t>::max());
242   GlobalInstrumentDescriptor descriptor;
243   descriptor.value_type = ValueType::kInt64;
244   descriptor.instrument_type = InstrumentType::kCallbackGauge;
245   descriptor.index = index;
246   descriptor.enable_by_default = enable_by_default;
247   descriptor.name = name;
248   descriptor.description = description;
249   descriptor.unit = unit;
250   descriptor.label_keys = {label_keys.begin(), label_keys.end()};
251   descriptor.optional_label_keys = {optional_label_keys.begin(),
252                                     optional_label_keys.end()};
253   instruments.push_back(std::move(descriptor));
254   GlobalCallbackInt64GaugeHandle handle;
255   handle.index = index;
256   return handle;
257 }
258 
259 GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle
RegisterCallbackDoubleGauge(absl::string_view name,absl::string_view description,absl::string_view unit,absl::Span<const absl::string_view> label_keys,absl::Span<const absl::string_view> optional_label_keys,bool enable_by_default)260 GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
261     absl::string_view name, absl::string_view description,
262     absl::string_view unit, absl::Span<const absl::string_view> label_keys,
263     absl::Span<const absl::string_view> optional_label_keys,
264     bool enable_by_default) {
265   auto& instruments = GetInstrumentList();
266   for (const auto& descriptor : instruments) {
267     if (descriptor.name == name) {
268       Crash(
269           absl::StrFormat("Metric name %s has already been registered.", name));
270     }
271   }
272   uint32_t index = instruments.size();
273   GPR_ASSERT(index < std::numeric_limits<uint32_t>::max());
274   GlobalInstrumentDescriptor descriptor;
275   descriptor.value_type = ValueType::kDouble;
276   descriptor.instrument_type = InstrumentType::kCallbackGauge;
277   descriptor.index = index;
278   descriptor.enable_by_default = enable_by_default;
279   descriptor.name = name;
280   descriptor.description = description;
281   descriptor.unit = unit;
282   descriptor.label_keys = {label_keys.begin(), label_keys.end()};
283   descriptor.optional_label_keys = {optional_label_keys.begin(),
284                                     optional_label_keys.end()};
285   instruments.push_back(std::move(descriptor));
286   GlobalCallbackDoubleGaugeHandle handle;
287   handle.index = index;
288   return handle;
289 }
290 
ForEach(absl::FunctionRef<void (const GlobalInstrumentDescriptor &)> f)291 void GlobalInstrumentsRegistry::ForEach(
292     absl::FunctionRef<void(const GlobalInstrumentDescriptor&)> f) {
293   for (const auto& instrument : GetInstrumentList()) {
294     f(instrument);
295   }
296 }
297 
298 const GlobalInstrumentsRegistry::GlobalInstrumentDescriptor&
GetInstrumentDescriptor(GlobalInstrumentHandle handle)299 GlobalInstrumentsRegistry::GetInstrumentDescriptor(
300     GlobalInstrumentHandle handle) {
301   return GetInstrumentList().at(handle.index);
302 }
303 
RegisteredMetricCallback(GlobalStatsPluginRegistry::StatsPluginGroup & stats_plugin_group,absl::AnyInvocable<void (CallbackMetricReporter &)> callback,std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle> metrics,Duration min_interval)304 RegisteredMetricCallback::RegisteredMetricCallback(
305     GlobalStatsPluginRegistry::StatsPluginGroup& stats_plugin_group,
306     absl::AnyInvocable<void(CallbackMetricReporter&)> callback,
307     std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle> metrics,
308     Duration min_interval)
309     : stats_plugin_group_(stats_plugin_group),
310       callback_(std::move(callback)),
311       metrics_(std::move(metrics)),
312       min_interval_(min_interval) {
313   for (auto& state : stats_plugin_group_.plugins_state_) {
314     state.plugin->AddCallback(this);
315   }
316 }
317 
~RegisteredMetricCallback()318 RegisteredMetricCallback::~RegisteredMetricCallback() {
319   for (auto& state : stats_plugin_group_.plugins_state_) {
320     state.plugin->RemoveCallback(this);
321   }
322 }
323 
324 std::unique_ptr<RegisteredMetricCallback>
RegisterCallback(absl::AnyInvocable<void (CallbackMetricReporter &)> callback,std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle> metrics,Duration min_interval)325 GlobalStatsPluginRegistry::StatsPluginGroup::RegisterCallback(
326     absl::AnyInvocable<void(CallbackMetricReporter&)> callback,
327     std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle> metrics,
328     Duration min_interval) {
329   return std::make_unique<RegisteredMetricCallback>(
330       *this, std::move(callback), std::move(metrics), min_interval);
331 }
332 
AddClientCallTracers(const Slice & path,bool registered_method,grpc_call_context_element * call_context)333 void GlobalStatsPluginRegistry::StatsPluginGroup::AddClientCallTracers(
334     const Slice& path, bool registered_method,
335     grpc_call_context_element* call_context) {
336   for (auto& state : plugins_state_) {
337     auto* call_tracer = state.plugin->GetClientCallTracer(
338         path, registered_method, state.scope_config);
339     if (call_tracer != nullptr) {
340       AddClientCallTracerToContext(call_context, call_tracer);
341     }
342   }
343 }
344 
AddServerCallTracers(grpc_call_context_element * call_context)345 void GlobalStatsPluginRegistry::StatsPluginGroup::AddServerCallTracers(
346     grpc_call_context_element* call_context) {
347   for (auto& state : plugins_state_) {
348     auto* call_tracer = state.plugin->GetServerCallTracer(state.scope_config);
349     if (call_tracer != nullptr) {
350       AddServerCallTracerToContext(call_context, call_tracer);
351     }
352   }
353 }
354 
355 NoDestruct<Mutex> GlobalStatsPluginRegistry::mutex_;
356 NoDestruct<std::vector<std::shared_ptr<StatsPlugin>>>
357     GlobalStatsPluginRegistry::plugins_;
358 
RegisterStatsPlugin(std::shared_ptr<StatsPlugin> plugin)359 void GlobalStatsPluginRegistry::RegisterStatsPlugin(
360     std::shared_ptr<StatsPlugin> plugin) {
361   MutexLock lock(&*mutex_);
362   plugins_->push_back(std::move(plugin));
363 }
364 
365 GlobalStatsPluginRegistry::StatsPluginGroup
GetStatsPluginsForChannel(const experimental::StatsPluginChannelScope & scope)366 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
367     const experimental::StatsPluginChannelScope& scope) {
368   MutexLock lock(&*mutex_);
369   StatsPluginGroup group;
370   for (const auto& plugin : *plugins_) {
371     bool is_enabled = false;
372     std::shared_ptr<StatsPlugin::ScopeConfig> config;
373     std::tie(is_enabled, config) = plugin->IsEnabledForChannel(scope);
374     if (is_enabled) {
375       group.AddStatsPlugin(plugin, std::move(config));
376     }
377   }
378   return group;
379 }
380 
381 GlobalStatsPluginRegistry::StatsPluginGroup
GetStatsPluginsForServer(const ChannelArgs & args)382 GlobalStatsPluginRegistry::GetStatsPluginsForServer(const ChannelArgs& args) {
383   MutexLock lock(&*mutex_);
384   StatsPluginGroup group;
385   for (const auto& plugin : *plugins_) {
386     bool is_enabled = false;
387     std::shared_ptr<StatsPlugin::ScopeConfig> config;
388     std::tie(is_enabled, config) = plugin->IsEnabledForServer(args);
389     if (is_enabled) {
390       group.AddStatsPlugin(plugin, std::move(config));
391     }
392   }
393   return group;
394 }
395 
396 }  // namespace grpc_core
397