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