1 //
2 //
3 // Copyright 2023 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <grpc/support/port_platform.h>
20
21 #include "src/cpp/ext/otel/otel_plugin.h"
22
23 #include <memory>
24 #include <type_traits>
25 #include <utility>
26
27 #include "opentelemetry/metrics/meter.h"
28 #include "opentelemetry/metrics/meter_provider.h"
29 #include "opentelemetry/metrics/sync_instruments.h"
30 #include "opentelemetry/nostd/shared_ptr.h"
31 #include "opentelemetry/nostd/unique_ptr.h"
32 #include "opentelemetry/nostd/variant.h"
33
34 #include <grpc/support/log.h>
35 #include <grpcpp/ext/otel_plugin.h>
36 #include <grpcpp/version_info.h>
37
38 #include "src/core/client_channel/client_channel_filter.h"
39 #include "src/core/lib/channel/call_tracer.h"
40 #include "src/core/lib/channel/channel_args.h"
41 #include "src/core/lib/config/core_configuration.h"
42 #include "src/core/lib/gprpp/match.h"
43 #include "src/core/lib/surface/channel_stack_type.h"
44 #include "src/cpp/ext/otel/key_value_iterable.h"
45 #include "src/cpp/ext/otel/otel_client_call_tracer.h"
46 #include "src/cpp/ext/otel/otel_server_call_tracer.h"
47
48 namespace grpc {
49 namespace internal {
50
OpenTelemetryMethodKey()51 absl::string_view OpenTelemetryMethodKey() { return "grpc.method"; }
52
OpenTelemetryStatusKey()53 absl::string_view OpenTelemetryStatusKey() { return "grpc.status"; }
54
OpenTelemetryTargetKey()55 absl::string_view OpenTelemetryTargetKey() { return "grpc.target"; }
56
57 namespace {
BaseMetrics()58 absl::flat_hash_set<std::string> BaseMetrics() {
59 absl::flat_hash_set<std::string> base_metrics{
60 std::string(grpc::OpenTelemetryPluginBuilder::
61 kClientAttemptStartedInstrumentName),
62 std::string(grpc::OpenTelemetryPluginBuilder::
63 kClientAttemptDurationInstrumentName),
64 std::string(
65 grpc::OpenTelemetryPluginBuilder::
66 kClientAttemptSentTotalCompressedMessageSizeInstrumentName),
67 std::string(
68 grpc::OpenTelemetryPluginBuilder::
69 kClientAttemptRcvdTotalCompressedMessageSizeInstrumentName),
70 std::string(
71 grpc::OpenTelemetryPluginBuilder::kServerCallStartedInstrumentName),
72 std::string(
73 grpc::OpenTelemetryPluginBuilder::kServerCallDurationInstrumentName),
74 std::string(grpc::OpenTelemetryPluginBuilder::
75 kServerCallSentTotalCompressedMessageSizeInstrumentName),
76 std::string(grpc::OpenTelemetryPluginBuilder::
77 kServerCallRcvdTotalCompressedMessageSizeInstrumentName)};
78 grpc_core::GlobalInstrumentsRegistry::ForEach(
79 [&](const grpc_core::GlobalInstrumentsRegistry::
80 GlobalInstrumentDescriptor& descriptor) {
81 if (descriptor.enable_by_default) {
82 base_metrics.emplace(descriptor.name);
83 }
84 });
85 return base_metrics;
86 }
87 } // namespace
88
89 class OpenTelemetryPlugin::NPCMetricsKeyValueIterable
90 : public opentelemetry::common::KeyValueIterable {
91 public:
NPCMetricsKeyValueIterable(absl::Span<const absl::string_view> label_keys,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_label_keys,absl::Span<const absl::string_view> optional_label_values,const OptionalLabelsBitSet & optional_labels_bits)92 NPCMetricsKeyValueIterable(
93 absl::Span<const absl::string_view> label_keys,
94 absl::Span<const absl::string_view> label_values,
95 absl::Span<const absl::string_view> optional_label_keys,
96 absl::Span<const absl::string_view> optional_label_values,
97 const OptionalLabelsBitSet& optional_labels_bits)
98 : label_keys_(label_keys),
99 label_values_(label_values),
100 optional_label_keys_(optional_label_keys),
101 optional_label_values_(optional_label_values),
102 optional_labels_bits_(optional_labels_bits) {}
103
ForEachKeyValue(opentelemetry::nostd::function_ref<bool (opentelemetry::nostd::string_view,opentelemetry::common::AttributeValue)> callback) const104 bool ForEachKeyValue(opentelemetry::nostd::function_ref<
105 bool(opentelemetry::nostd::string_view,
106 opentelemetry::common::AttributeValue)>
107 callback) const noexcept override {
108 for (size_t i = 0; i < label_keys_.size(); i++) {
109 if (!callback(AbslStrViewToOpenTelemetryStrView(label_keys_[i]),
110 AbslStrViewToOpenTelemetryStrView(label_values_[i]))) {
111 return false;
112 }
113 }
114 // Since we are saving the optional label values as std::string for callback
115 // gauges, we want to minimize memory usage by filtering out the disabled
116 // optional label values.
117 bool filtered = optional_label_values_.size() < optional_label_keys_.size();
118 for (size_t i = 0, j = 0; i < optional_label_keys_.size(); ++i) {
119 if (!optional_labels_bits_.test(i)) {
120 if (!filtered) ++j;
121 continue;
122 }
123 if (!callback(
124 AbslStrViewToOpenTelemetryStrView(optional_label_keys_[i]),
125 AbslStrViewToOpenTelemetryStrView(optional_label_values_[j++]))) {
126 return false;
127 }
128 }
129 return true;
130 }
131
size() const132 size_t size() const noexcept override {
133 return label_keys_.size() + optional_labels_bits_.count();
134 }
135
136 private:
137 absl::Span<const absl::string_view> label_keys_;
138 absl::Span<const absl::string_view> label_values_;
139 absl::Span<const absl::string_view> optional_label_keys_;
140 absl::Span<const absl::string_view> optional_label_values_;
141 const OptionalLabelsBitSet& optional_labels_bits_;
142 };
143
144 //
145 // OpenTelemetryPluginBuilderImpl
146 //
147
OpenTelemetryPluginBuilderImpl()148 OpenTelemetryPluginBuilderImpl::OpenTelemetryPluginBuilderImpl()
149 : metrics_(BaseMetrics()) {}
150
151 OpenTelemetryPluginBuilderImpl::~OpenTelemetryPluginBuilderImpl() = default;
152
153 OpenTelemetryPluginBuilderImpl&
SetMeterProvider(std::shared_ptr<opentelemetry::metrics::MeterProvider> meter_provider)154 OpenTelemetryPluginBuilderImpl::SetMeterProvider(
155 std::shared_ptr<opentelemetry::metrics::MeterProvider> meter_provider) {
156 meter_provider_ = std::move(meter_provider);
157 return *this;
158 }
159
EnableMetrics(absl::Span<const absl::string_view> metric_names)160 OpenTelemetryPluginBuilderImpl& OpenTelemetryPluginBuilderImpl::EnableMetrics(
161 absl::Span<const absl::string_view> metric_names) {
162 for (const auto& metric_name : metric_names) {
163 metrics_.emplace(metric_name);
164 }
165 return *this;
166 }
167
DisableMetrics(absl::Span<const absl::string_view> metric_names)168 OpenTelemetryPluginBuilderImpl& OpenTelemetryPluginBuilderImpl::DisableMetrics(
169 absl::Span<const absl::string_view> metric_names) {
170 for (const auto& metric_name : metric_names) {
171 metrics_.erase(metric_name);
172 }
173 return *this;
174 }
175
176 OpenTelemetryPluginBuilderImpl&
DisableAllMetrics()177 OpenTelemetryPluginBuilderImpl::DisableAllMetrics() {
178 metrics_.clear();
179 return *this;
180 }
181
182 OpenTelemetryPluginBuilderImpl&
SetTargetAttributeFilter(absl::AnyInvocable<bool (absl::string_view)const> target_attribute_filter)183 OpenTelemetryPluginBuilderImpl::SetTargetAttributeFilter(
184 absl::AnyInvocable<bool(absl::string_view /*target*/) const>
185 target_attribute_filter) {
186 target_attribute_filter_ = std::move(target_attribute_filter);
187 return *this;
188 }
189
190 OpenTelemetryPluginBuilderImpl&
SetGenericMethodAttributeFilter(absl::AnyInvocable<bool (absl::string_view)const> generic_method_attribute_filter)191 OpenTelemetryPluginBuilderImpl::SetGenericMethodAttributeFilter(
192 absl::AnyInvocable<bool(absl::string_view /*generic_method*/) const>
193 generic_method_attribute_filter) {
194 generic_method_attribute_filter_ = std::move(generic_method_attribute_filter);
195 return *this;
196 }
197
198 OpenTelemetryPluginBuilderImpl&
SetServerSelector(absl::AnyInvocable<bool (const grpc_core::ChannelArgs &)const> server_selector)199 OpenTelemetryPluginBuilderImpl::SetServerSelector(
200 absl::AnyInvocable<bool(const grpc_core::ChannelArgs& /*args*/) const>
201 server_selector) {
202 server_selector_ = std::move(server_selector);
203 return *this;
204 }
205
AddPluginOption(std::unique_ptr<InternalOpenTelemetryPluginOption> option)206 OpenTelemetryPluginBuilderImpl& OpenTelemetryPluginBuilderImpl::AddPluginOption(
207 std::unique_ptr<InternalOpenTelemetryPluginOption> option) {
208 // We allow a limit of 64 plugin options to be registered at this time.
209 GPR_ASSERT(plugin_options_.size() < 64);
210 plugin_options_.push_back(std::move(option));
211 return *this;
212 }
213
214 OpenTelemetryPluginBuilderImpl&
AddOptionalLabel(absl::string_view optional_label_key)215 OpenTelemetryPluginBuilderImpl::AddOptionalLabel(
216 absl::string_view optional_label_key) {
217 optional_label_keys_.emplace(optional_label_key);
218 return *this;
219 }
220
221 OpenTelemetryPluginBuilderImpl&
SetChannelScopeFilter(absl::AnyInvocable<bool (const OpenTelemetryPluginBuilder::ChannelScope &)const> channel_scope_filter)222 OpenTelemetryPluginBuilderImpl::SetChannelScopeFilter(
223 absl::AnyInvocable<
224 bool(const OpenTelemetryPluginBuilder::ChannelScope& /*scope*/) const>
225 channel_scope_filter) {
226 channel_scope_filter_ = std::move(channel_scope_filter);
227 return *this;
228 }
229
BuildAndRegisterGlobal()230 absl::Status OpenTelemetryPluginBuilderImpl::BuildAndRegisterGlobal() {
231 if (meter_provider_ == nullptr) {
232 return absl::OkStatus();
233 }
234 grpc_core::GlobalStatsPluginRegistry::RegisterStatsPlugin(
235 std::make_shared<OpenTelemetryPlugin>(
236 metrics_, meter_provider_, std::move(target_attribute_filter_),
237 std::move(generic_method_attribute_filter_),
238 std::move(server_selector_), std::move(plugin_options_),
239 std::move(optional_label_keys_), std::move(channel_scope_filter_)));
240 return absl::OkStatus();
241 }
242
CallbackMetricReporter(OpenTelemetryPlugin * ot_plugin,grpc_core::RegisteredMetricCallback * key)243 OpenTelemetryPlugin::CallbackMetricReporter::CallbackMetricReporter(
244 OpenTelemetryPlugin* ot_plugin, grpc_core::RegisteredMetricCallback* key)
245 : ot_plugin_(ot_plugin), key_(key) {
246 // Since we are updating the timestamp and updating the cache for all
247 // registered instruments in a RegisteredMetricCallback, we will need to
248 // clear all the cache cells for this RegisteredMetricCallback first, so
249 // that if a particular combination of labels was previously present but
250 // is no longer present, we won't continue to report it.
251 for (const auto& handle : key->metrics()) {
252 grpc_core::Match(
253 handle,
254 [&](const grpc_core::GlobalInstrumentsRegistry::
255 GlobalCallbackInt64GaugeHandle& handle) {
256 auto& callback_gauge_state =
257 absl::get<std::unique_ptr<CallbackGaugeState<int64_t>>>(
258 ot_plugin_->instruments_data_.at(handle.index).instrument);
259 callback_gauge_state->caches[key].clear();
260 },
261 [&](const grpc_core::GlobalInstrumentsRegistry::
262 GlobalCallbackDoubleGaugeHandle& handle) {
263 auto& callback_gauge_state =
264 absl::get<std::unique_ptr<CallbackGaugeState<double>>>(
265 ot_plugin_->instruments_data_.at(handle.index).instrument);
266 callback_gauge_state->caches[key].clear();
267 });
268 }
269 }
270
Report(grpc_core::GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle handle,int64_t value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)271 void OpenTelemetryPlugin::CallbackMetricReporter::Report(
272 grpc_core::GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle handle,
273 int64_t value, absl::Span<const absl::string_view> label_values,
274 absl::Span<const absl::string_view> optional_values) {
275 const auto& instrument_data = ot_plugin_->instruments_data_.at(handle.index);
276 auto* callback_gauge_state =
277 absl::get_if<std::unique_ptr<CallbackGaugeState<int64_t>>>(
278 &instrument_data.instrument);
279 GPR_ASSERT(callback_gauge_state != nullptr);
280 const auto& descriptor =
281 grpc_core::GlobalInstrumentsRegistry::GetInstrumentDescriptor(handle);
282 GPR_ASSERT(descriptor.label_keys.size() == label_values.size());
283 GPR_ASSERT(descriptor.optional_label_keys.size() == optional_values.size());
284 auto& cell = (*callback_gauge_state)->caches.at(key_);
285 std::vector<std::string> key;
286 key.reserve(label_values.size() +
287 instrument_data.optional_labels_bits.count());
288 for (const absl::string_view value : label_values) {
289 key.emplace_back(value);
290 }
291 for (size_t i = 0; i < optional_values.size(); ++i) {
292 if (instrument_data.optional_labels_bits.test(i)) {
293 key.emplace_back(optional_values[i]);
294 }
295 }
296 cell.insert_or_assign(std::move(key), value);
297 }
298
Report(grpc_core::GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle handle,double value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)299 void OpenTelemetryPlugin::CallbackMetricReporter::Report(
300 grpc_core::GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle
301 handle,
302 double value, absl::Span<const absl::string_view> label_values,
303 absl::Span<const absl::string_view> optional_values) {
304 const auto& instrument_data = ot_plugin_->instruments_data_.at(handle.index);
305 auto* callback_gauge_state =
306 absl::get_if<std::unique_ptr<CallbackGaugeState<double>>>(
307 &instrument_data.instrument);
308 GPR_ASSERT(callback_gauge_state != nullptr);
309 const auto& descriptor =
310 grpc_core::GlobalInstrumentsRegistry::GetInstrumentDescriptor(handle);
311 GPR_ASSERT(descriptor.label_keys.size() == label_values.size());
312 GPR_ASSERT(descriptor.optional_label_keys.size() == optional_values.size());
313 auto& cell = (*callback_gauge_state)->caches.at(key_);
314 std::vector<std::string> key;
315 key.reserve(label_values.size() +
316 instrument_data.optional_labels_bits.count());
317 for (const absl::string_view value : label_values) {
318 key.emplace_back(value);
319 }
320 for (size_t i = 0; i < optional_values.size(); ++i) {
321 if (instrument_data.optional_labels_bits.test(i)) {
322 key.emplace_back(optional_values[i]);
323 }
324 }
325 cell.insert_or_assign(std::move(key), value);
326 }
327
OpenTelemetryPlugin(const absl::flat_hash_set<std::string> & metrics,opentelemetry::nostd::shared_ptr<opentelemetry::metrics::MeterProvider> meter_provider,absl::AnyInvocable<bool (absl::string_view)const> target_attribute_filter,absl::AnyInvocable<bool (absl::string_view)const> generic_method_attribute_filter,absl::AnyInvocable<bool (const grpc_core::ChannelArgs &)const> server_selector,std::vector<std::unique_ptr<InternalOpenTelemetryPluginOption>> plugin_options,const std::set<absl::string_view> & optional_label_keys,absl::AnyInvocable<bool (const OpenTelemetryPluginBuilder::ChannelScope &)const> channel_scope_filter)328 OpenTelemetryPlugin::OpenTelemetryPlugin(
329 const absl::flat_hash_set<std::string>& metrics,
330 opentelemetry::nostd::shared_ptr<opentelemetry::metrics::MeterProvider>
331 meter_provider,
332 absl::AnyInvocable<bool(absl::string_view /*target*/) const>
333 target_attribute_filter,
334 absl::AnyInvocable<bool(absl::string_view /*generic_method*/) const>
335 generic_method_attribute_filter,
336 absl::AnyInvocable<bool(const grpc_core::ChannelArgs& /*args*/) const>
337 server_selector,
338 std::vector<std::unique_ptr<InternalOpenTelemetryPluginOption>>
339 plugin_options,
340 const std::set<absl::string_view>& optional_label_keys,
341 absl::AnyInvocable<
342 bool(const OpenTelemetryPluginBuilder::ChannelScope& /*scope*/) const>
343 channel_scope_filter)
344 : meter_provider_(std::move(meter_provider)),
345 server_selector_(std::move(server_selector)),
346 target_attribute_filter_(std::move(target_attribute_filter)),
347 generic_method_attribute_filter_(
348 std::move(generic_method_attribute_filter)),
349 plugin_options_(std::move(plugin_options)),
350 channel_scope_filter_(std::move(channel_scope_filter)) {
351 auto meter = meter_provider_->GetMeter("grpc-c++", GRPC_CPP_VERSION_STRING);
352 // Per-call metrics.
353 if (metrics.contains(grpc::OpenTelemetryPluginBuilder::
354 kClientAttemptStartedInstrumentName)) {
355 client_.attempt.started = meter->CreateUInt64Counter(
356 std::string(grpc::OpenTelemetryPluginBuilder::
357 kClientAttemptStartedInstrumentName),
358 "Number of client call attempts started", "{attempt}");
359 }
360 if (metrics.contains(grpc::OpenTelemetryPluginBuilder::
361 kClientAttemptDurationInstrumentName)) {
362 client_.attempt.duration = meter->CreateDoubleHistogram(
363 std::string(grpc::OpenTelemetryPluginBuilder::
364 kClientAttemptDurationInstrumentName),
365 "End-to-end time taken to complete a client call attempt", "s");
366 }
367 if (metrics.contains(
368 grpc::OpenTelemetryPluginBuilder::
369 kClientAttemptSentTotalCompressedMessageSizeInstrumentName)) {
370 client_.attempt.sent_total_compressed_message_size =
371 meter->CreateUInt64Histogram(
372 std::string(
373 grpc::OpenTelemetryPluginBuilder::
374 kClientAttemptSentTotalCompressedMessageSizeInstrumentName),
375 "Compressed message bytes sent per client call attempt", "By");
376 }
377 if (metrics.contains(
378 grpc::OpenTelemetryPluginBuilder::
379 kClientAttemptRcvdTotalCompressedMessageSizeInstrumentName)) {
380 client_.attempt.rcvd_total_compressed_message_size =
381 meter->CreateUInt64Histogram(
382 std::string(
383 grpc::OpenTelemetryPluginBuilder::
384 kClientAttemptRcvdTotalCompressedMessageSizeInstrumentName),
385 "Compressed message bytes received per call attempt", "By");
386 }
387 if (metrics.contains(
388 grpc::OpenTelemetryPluginBuilder::kServerCallStartedInstrumentName)) {
389 server_.call.started = meter->CreateUInt64Counter(
390 std::string(
391 grpc::OpenTelemetryPluginBuilder::kServerCallStartedInstrumentName),
392 "Number of server calls started", "{call}");
393 }
394 if (metrics.contains(grpc::OpenTelemetryPluginBuilder::
395 kServerCallDurationInstrumentName)) {
396 server_.call.duration = meter->CreateDoubleHistogram(
397 std::string(grpc::OpenTelemetryPluginBuilder::
398 kServerCallDurationInstrumentName),
399 "End-to-end time taken to complete a call from server transport's "
400 "perspective",
401 "s");
402 }
403 if (metrics.contains(
404 grpc::OpenTelemetryPluginBuilder::
405 kServerCallSentTotalCompressedMessageSizeInstrumentName)) {
406 server_.call.sent_total_compressed_message_size =
407 meter->CreateUInt64Histogram(
408 std::string(
409 grpc::OpenTelemetryPluginBuilder::
410 kServerCallSentTotalCompressedMessageSizeInstrumentName),
411 "Compressed message bytes sent per server call", "By");
412 }
413 if (metrics.contains(
414 grpc::OpenTelemetryPluginBuilder::
415 kServerCallRcvdTotalCompressedMessageSizeInstrumentName)) {
416 server_.call.rcvd_total_compressed_message_size =
417 meter->CreateUInt64Histogram(
418 std::string(
419 grpc::OpenTelemetryPluginBuilder::
420 kServerCallRcvdTotalCompressedMessageSizeInstrumentName),
421 "Compressed message bytes received per server call", "By");
422 }
423 // Store optional label keys for per call metrics
424 GPR_ASSERT(static_cast<size_t>(
425 grpc_core::ClientCallTracer::CallAttemptTracer::
426 OptionalLabelKey::kSize) <= kOptionalLabelsSizeLimit);
427 for (const auto& key : optional_label_keys) {
428 auto optional_key = OptionalLabelStringToKey(key);
429 if (optional_key.has_value()) {
430 per_call_optional_label_bits_.set(
431 static_cast<size_t>(optional_key.value()));
432 }
433 }
434 // Non-per-call metrics.
435 grpc_core::GlobalInstrumentsRegistry::ForEach(
436 [&, this](const grpc_core::GlobalInstrumentsRegistry::
437 GlobalInstrumentDescriptor& descriptor) {
438 GPR_ASSERT(descriptor.optional_label_keys.size() <=
439 kOptionalLabelsSizeLimit);
440 if (instruments_data_.size() < descriptor.index + 1) {
441 instruments_data_.resize(descriptor.index + 1);
442 }
443 if (!metrics.contains(descriptor.name)) {
444 return;
445 }
446 switch (descriptor.instrument_type) {
447 case grpc_core::GlobalInstrumentsRegistry::InstrumentType::kCounter:
448 switch (descriptor.value_type) {
449 case grpc_core::GlobalInstrumentsRegistry::ValueType::kUInt64:
450 instruments_data_[descriptor.index].instrument =
451 meter->CreateUInt64Counter(
452 std::string(descriptor.name),
453 std::string(descriptor.description),
454 std::string(descriptor.unit));
455 break;
456 case grpc_core::GlobalInstrumentsRegistry::ValueType::kDouble:
457 instruments_data_[descriptor.index].instrument =
458 meter->CreateDoubleCounter(
459 std::string(descriptor.name),
460 std::string(descriptor.description),
461 std::string(descriptor.unit));
462 break;
463 default:
464 grpc_core::Crash(
465 absl::StrFormat("Unknown or unsupported value type: %d",
466 descriptor.value_type));
467 }
468 break;
469 case grpc_core::GlobalInstrumentsRegistry::InstrumentType::kHistogram:
470 switch (descriptor.value_type) {
471 case grpc_core::GlobalInstrumentsRegistry::ValueType::kUInt64:
472 instruments_data_[descriptor.index].instrument =
473 meter->CreateUInt64Histogram(
474 std::string(descriptor.name),
475 std::string(descriptor.description),
476 std::string(descriptor.unit));
477 break;
478 case grpc_core::GlobalInstrumentsRegistry::ValueType::kDouble:
479 instruments_data_[descriptor.index].instrument =
480 meter->CreateDoubleHistogram(
481 std::string(descriptor.name),
482 std::string(descriptor.description),
483 std::string(descriptor.unit));
484 break;
485 default:
486 grpc_core::Crash(
487 absl::StrFormat("Unknown or unsupported value type: %d",
488 descriptor.value_type));
489 }
490 break;
491 case grpc_core::GlobalInstrumentsRegistry::InstrumentType::kGauge:
492 grpc_core::Crash(
493 "Non-callback gauge is not supported and will be deleted in "
494 "the future.");
495 break;
496 case grpc_core::GlobalInstrumentsRegistry::InstrumentType::
497 kCallbackGauge:
498 switch (descriptor.value_type) {
499 case grpc_core::GlobalInstrumentsRegistry::ValueType::kInt64: {
500 auto observable_state =
501 std::make_unique<CallbackGaugeState<int64_t>>();
502 observable_state->id = descriptor.index;
503 observable_state->ot_plugin = this;
504 observable_state->instrument =
505 meter->CreateInt64ObservableGauge(
506 std::string(descriptor.name),
507 std::string(descriptor.description),
508 std::string(descriptor.unit));
509 instruments_data_[descriptor.index].instrument =
510 std::move(observable_state);
511 break;
512 }
513 case grpc_core::GlobalInstrumentsRegistry::ValueType::kDouble: {
514 auto observable_state =
515 std::make_unique<CallbackGaugeState<double>>();
516 observable_state->id = descriptor.index;
517 observable_state->ot_plugin = this;
518 observable_state->instrument =
519 meter->CreateDoubleObservableGauge(
520 std::string(descriptor.name),
521 std::string(descriptor.description),
522 std::string(descriptor.unit));
523 instruments_data_[descriptor.index].instrument =
524 std::move(observable_state);
525 break;
526 }
527 default:
528 grpc_core::Crash(
529 absl::StrFormat("Unknown or unsupported value type: %d",
530 descriptor.value_type));
531 }
532 break;
533 default:
534 grpc_core::Crash(absl::StrFormat("Unknown instrument_type: %d",
535 descriptor.instrument_type));
536 }
537 for (size_t i = 0; i < descriptor.optional_label_keys.size(); ++i) {
538 if (optional_label_keys.find(descriptor.optional_label_keys[i]) !=
539 optional_label_keys.end()) {
540 instruments_data_[descriptor.index].optional_labels_bits.set(i);
541 }
542 }
543 });
544 }
545
546 namespace {
547 constexpr absl::string_view kLocality = "grpc.lb.locality";
548 }
549
OptionalLabelKeyToString(grpc_core::ClientCallTracer::CallAttemptTracer::OptionalLabelKey key)550 absl::string_view OpenTelemetryPlugin::OptionalLabelKeyToString(
551 grpc_core::ClientCallTracer::CallAttemptTracer::OptionalLabelKey key) {
552 switch (key) {
553 case grpc_core::ClientCallTracer::CallAttemptTracer::OptionalLabelKey::
554 kLocality:
555 return kLocality;
556 default:
557 grpc_core::Crash("Illegal OptionalLabelKey index");
558 }
559 }
560
561 absl::optional<grpc_core::ClientCallTracer::CallAttemptTracer::OptionalLabelKey>
OptionalLabelStringToKey(absl::string_view key)562 OpenTelemetryPlugin::OptionalLabelStringToKey(absl::string_view key) {
563 if (key == kLocality) {
564 return grpc_core::ClientCallTracer::CallAttemptTracer::OptionalLabelKey::
565 kLocality;
566 }
567 return absl::nullopt;
568 }
569
570 std::pair<bool, std::shared_ptr<grpc_core::StatsPlugin::ScopeConfig>>
IsEnabledForChannel(const OpenTelemetryPluginBuilder::ChannelScope & scope) const571 OpenTelemetryPlugin::IsEnabledForChannel(
572 const OpenTelemetryPluginBuilder::ChannelScope& scope) const {
573 if (channel_scope_filter_ == nullptr || channel_scope_filter_(scope)) {
574 return {true, std::make_shared<ClientScopeConfig>(this, scope)};
575 }
576 return {false, nullptr};
577 }
578
579 std::pair<bool, std::shared_ptr<grpc_core::StatsPlugin::ScopeConfig>>
IsEnabledForServer(const grpc_core::ChannelArgs & args) const580 OpenTelemetryPlugin::IsEnabledForServer(
581 const grpc_core::ChannelArgs& args) const {
582 // Return true only if there is no server selector registered or if the server
583 // selector returns true.
584 if (server_selector_ == nullptr || server_selector_(args)) {
585 return {true, std::make_shared<ServerScopeConfig>(this, args)};
586 }
587 return {false, nullptr};
588 }
589
AddCounter(grpc_core::GlobalInstrumentsRegistry::GlobalUInt64CounterHandle handle,uint64_t value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)590 void OpenTelemetryPlugin::AddCounter(
591 grpc_core::GlobalInstrumentsRegistry::GlobalUInt64CounterHandle handle,
592 uint64_t value, absl::Span<const absl::string_view> label_values,
593 absl::Span<const absl::string_view> optional_values) {
594 const auto& instrument_data = instruments_data_.at(handle.index);
595 if (absl::holds_alternative<Disabled>(instrument_data.instrument)) {
596 // This instrument is disabled.
597 return;
598 }
599 GPR_ASSERT(absl::holds_alternative<
600 std::unique_ptr<opentelemetry::metrics::Counter<uint64_t>>>(
601 instrument_data.instrument));
602 const auto& descriptor =
603 grpc_core::GlobalInstrumentsRegistry::GetInstrumentDescriptor(handle);
604 GPR_ASSERT(descriptor.label_keys.size() == label_values.size());
605 GPR_ASSERT(descriptor.optional_label_keys.size() == optional_values.size());
606 absl::get<std::unique_ptr<opentelemetry::metrics::Counter<uint64_t>>>(
607 instrument_data.instrument)
608 ->Add(value, NPCMetricsKeyValueIterable(
609 descriptor.label_keys, label_values,
610 descriptor.optional_label_keys, optional_values,
611 instrument_data.optional_labels_bits));
612 }
613
AddCounter(grpc_core::GlobalInstrumentsRegistry::GlobalDoubleCounterHandle handle,double value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)614 void OpenTelemetryPlugin::AddCounter(
615 grpc_core::GlobalInstrumentsRegistry::GlobalDoubleCounterHandle handle,
616 double value, absl::Span<const absl::string_view> label_values,
617 absl::Span<const absl::string_view> optional_values) {
618 const auto& instrument_data = instruments_data_.at(handle.index);
619 if (absl::holds_alternative<Disabled>(instrument_data.instrument)) {
620 // This instrument is disabled.
621 return;
622 }
623 GPR_ASSERT(absl::holds_alternative<
624 std::unique_ptr<opentelemetry::metrics::Counter<double>>>(
625 instrument_data.instrument));
626 const auto& descriptor =
627 grpc_core::GlobalInstrumentsRegistry::GetInstrumentDescriptor(handle);
628 GPR_ASSERT(descriptor.label_keys.size() == label_values.size());
629 GPR_ASSERT(descriptor.optional_label_keys.size() == optional_values.size());
630 absl::get<std::unique_ptr<opentelemetry::metrics::Counter<double>>>(
631 instrument_data.instrument)
632 ->Add(value, NPCMetricsKeyValueIterable(
633 descriptor.label_keys, label_values,
634 descriptor.optional_label_keys, optional_values,
635 instrument_data.optional_labels_bits));
636 }
637
RecordHistogram(grpc_core::GlobalInstrumentsRegistry::GlobalUInt64HistogramHandle handle,uint64_t value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)638 void OpenTelemetryPlugin::RecordHistogram(
639 grpc_core::GlobalInstrumentsRegistry::GlobalUInt64HistogramHandle handle,
640 uint64_t value, absl::Span<const absl::string_view> label_values,
641 absl::Span<const absl::string_view> optional_values) {
642 const auto& instrument_data = instruments_data_.at(handle.index);
643 if (absl::holds_alternative<Disabled>(instrument_data.instrument)) {
644 // This instrument is disabled.
645 return;
646 }
647 GPR_ASSERT(absl::holds_alternative<
648 std::unique_ptr<opentelemetry::metrics::Histogram<uint64_t>>>(
649 instrument_data.instrument));
650 const auto& descriptor =
651 grpc_core::GlobalInstrumentsRegistry::GetInstrumentDescriptor(handle);
652 GPR_ASSERT(descriptor.label_keys.size() == label_values.size());
653 GPR_ASSERT(descriptor.optional_label_keys.size() == optional_values.size());
654 absl::get<std::unique_ptr<opentelemetry::metrics::Histogram<uint64_t>>>(
655 instrument_data.instrument)
656 ->Record(value,
657 NPCMetricsKeyValueIterable(descriptor.label_keys, label_values,
658 descriptor.optional_label_keys,
659 optional_values,
660 instrument_data.optional_labels_bits),
661 opentelemetry::context::Context{});
662 }
663
RecordHistogram(grpc_core::GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle handle,double value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)664 void OpenTelemetryPlugin::RecordHistogram(
665 grpc_core::GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle handle,
666 double value, absl::Span<const absl::string_view> label_values,
667 absl::Span<const absl::string_view> optional_values) {
668 const auto& instrument_data = instruments_data_.at(handle.index);
669 if (absl::holds_alternative<Disabled>(instrument_data.instrument)) {
670 // This instrument is disabled.
671 return;
672 }
673 GPR_ASSERT(absl::holds_alternative<
674 std::unique_ptr<opentelemetry::metrics::Histogram<double>>>(
675 instrument_data.instrument));
676 const auto& descriptor =
677 grpc_core::GlobalInstrumentsRegistry::GetInstrumentDescriptor(handle);
678 GPR_ASSERT(descriptor.label_keys.size() == label_values.size());
679 GPR_ASSERT(descriptor.optional_label_keys.size() == optional_values.size());
680 absl::get<std::unique_ptr<opentelemetry::metrics::Histogram<double>>>(
681 instrument_data.instrument)
682 ->Record(value,
683 NPCMetricsKeyValueIterable(descriptor.label_keys, label_values,
684 descriptor.optional_label_keys,
685 optional_values,
686 instrument_data.optional_labels_bits),
687 opentelemetry::context::Context{});
688 }
689
AddCallback(grpc_core::RegisteredMetricCallback * callback)690 void OpenTelemetryPlugin::AddCallback(
691 grpc_core::RegisteredMetricCallback* callback) {
692 std::vector<
693 absl::variant<CallbackGaugeState<int64_t>*, CallbackGaugeState<double>*>>
694 gauges_that_need_to_add_callback;
695 {
696 grpc_core::MutexLock lock(&mu_);
697 callback_timestamps_.emplace(callback, grpc_core::Timestamp::InfPast());
698 for (const auto& handle : callback->metrics()) {
699 grpc_core::Match(
700 handle,
701 [&](const grpc_core::GlobalInstrumentsRegistry::
702 GlobalCallbackInt64GaugeHandle& handle) {
703 const auto& instrument_data = instruments_data_.at(handle.index);
704 if (absl::holds_alternative<Disabled>(instrument_data.instrument)) {
705 // This instrument is disabled.
706 return;
707 }
708 auto* callback_gauge_state =
709 absl::get_if<std::unique_ptr<CallbackGaugeState<int64_t>>>(
710 &instrument_data.instrument);
711 GPR_ASSERT(callback_gauge_state != nullptr);
712 (*callback_gauge_state)
713 ->caches.emplace(callback,
714 CallbackGaugeState<int64_t>::Cache{});
715 if (!std::exchange((*callback_gauge_state)->ot_callback_registered,
716 true)) {
717 gauges_that_need_to_add_callback.push_back(
718 callback_gauge_state->get());
719 }
720 },
721 [&](const grpc_core::GlobalInstrumentsRegistry::
722 GlobalCallbackDoubleGaugeHandle& handle) {
723 const auto& instrument_data = instruments_data_.at(handle.index);
724 if (absl::holds_alternative<Disabled>(instrument_data.instrument)) {
725 // This instrument is disabled.
726 return;
727 }
728 auto* callback_gauge_state =
729 absl::get_if<std::unique_ptr<CallbackGaugeState<double>>>(
730 &instrument_data.instrument);
731 GPR_ASSERT(callback_gauge_state != nullptr);
732 (*callback_gauge_state)
733 ->caches.emplace(callback, CallbackGaugeState<double>::Cache{});
734 if (!std::exchange((*callback_gauge_state)->ot_callback_registered,
735 true)) {
736 gauges_that_need_to_add_callback.push_back(
737 callback_gauge_state->get());
738 }
739 });
740 }
741 }
742 // AddCallback internally grabs OpenTelemetry's observable_registry's lock. So
743 // we need to call it without our plugin lock otherwise we may deadlock.
744 for (const auto& gauge : gauges_that_need_to_add_callback) {
745 grpc_core::Match(
746 gauge,
747 [](CallbackGaugeState<int64_t>* gauge) {
748 gauge->instrument->AddCallback(
749 &CallbackGaugeState<int64_t>::CallbackGaugeCallback, gauge);
750 },
751 [](CallbackGaugeState<double>* gauge) {
752 gauge->instrument->AddCallback(
753 &CallbackGaugeState<double>::CallbackGaugeCallback, gauge);
754 });
755 }
756 }
757
RemoveCallback(grpc_core::RegisteredMetricCallback * callback)758 void OpenTelemetryPlugin::RemoveCallback(
759 grpc_core::RegisteredMetricCallback* callback) {
760 std::vector<
761 absl::variant<CallbackGaugeState<int64_t>*, CallbackGaugeState<double>*>>
762 gauges_that_need_to_remove_callback;
763 {
764 grpc_core::MutexLock lock(&mu_);
765 callback_timestamps_.erase(callback);
766 for (const auto& handle : callback->metrics()) {
767 grpc_core::Match(
768 handle,
769 [&](const grpc_core::GlobalInstrumentsRegistry::
770 GlobalCallbackInt64GaugeHandle& handle) {
771 const auto& instrument_data = instruments_data_.at(handle.index);
772 if (absl::holds_alternative<Disabled>(instrument_data.instrument)) {
773 // This instrument is disabled.
774 return;
775 }
776 auto* callback_gauge_state =
777 absl::get_if<std::unique_ptr<CallbackGaugeState<int64_t>>>(
778 &instrument_data.instrument);
779 GPR_ASSERT(callback_gauge_state != nullptr);
780 GPR_ASSERT((*callback_gauge_state)->ot_callback_registered);
781 GPR_ASSERT((*callback_gauge_state)->caches.erase(callback) == 1);
782 if ((*callback_gauge_state)->caches.empty()) {
783 gauges_that_need_to_remove_callback.push_back(
784 callback_gauge_state->get());
785 (*callback_gauge_state)->ot_callback_registered = false;
786 }
787 },
788 [&](const grpc_core::GlobalInstrumentsRegistry::
789 GlobalCallbackDoubleGaugeHandle& handle) {
790 const auto& instrument_data = instruments_data_.at(handle.index);
791 if (absl::holds_alternative<Disabled>(instrument_data.instrument)) {
792 // This instrument is disabled.
793 return;
794 }
795 auto* callback_gauge_state =
796 absl::get_if<std::unique_ptr<CallbackGaugeState<double>>>(
797 &instrument_data.instrument);
798 GPR_ASSERT(callback_gauge_state != nullptr);
799 GPR_ASSERT((*callback_gauge_state)->ot_callback_registered);
800 GPR_ASSERT((*callback_gauge_state)->caches.erase(callback) == 1);
801 if ((*callback_gauge_state)->caches.empty()) {
802 gauges_that_need_to_remove_callback.push_back(
803 callback_gauge_state->get());
804 (*callback_gauge_state)->ot_callback_registered = false;
805 }
806 });
807 }
808 }
809 // RemoveCallback internally grabs OpenTelemetry's observable_registry's lock.
810 // So we need to call it without our plugin lock otherwise we may deadlock.
811 for (const auto& gauge : gauges_that_need_to_remove_callback) {
812 grpc_core::Match(
813 gauge,
814 [](CallbackGaugeState<int64_t>* gauge) {
815 gauge->instrument->RemoveCallback(
816 &CallbackGaugeState<int64_t>::CallbackGaugeCallback, gauge);
817 },
818 [](CallbackGaugeState<double>* gauge) {
819 gauge->instrument->RemoveCallback(
820 &CallbackGaugeState<double>::CallbackGaugeCallback, gauge);
821 });
822 }
823 }
824
825 template <typename ValueType>
Observe(opentelemetry::metrics::ObserverResult & result,const Cache & cache)826 void OpenTelemetryPlugin::CallbackGaugeState<ValueType>::Observe(
827 opentelemetry::metrics::ObserverResult& result, const Cache& cache) {
828 const auto& descriptor =
829 grpc_core::GlobalInstrumentsRegistry::GetInstrumentDescriptor({id});
830 for (const auto& pair : cache) {
831 GPR_ASSERT(pair.first.size() <= (descriptor.label_keys.size() +
832 descriptor.optional_label_keys.size()));
833 auto& instrument_data = ot_plugin->instruments_data_.at(id);
834 opentelemetry::nostd::get<opentelemetry::nostd::shared_ptr<
835 opentelemetry::metrics::ObserverResultT<ValueType>>>(result)
836 ->Observe(pair.second,
837 NPCMetricsKeyValueIterable(
838 descriptor.label_keys,
839 absl::FixedArray<absl::string_view>(
840 pair.first.begin(),
841 pair.first.begin() + descriptor.label_keys.size()),
842 descriptor.optional_label_keys,
843 absl::FixedArray<absl::string_view>(
844 pair.first.begin() + descriptor.label_keys.size(),
845 pair.first.end()),
846 instrument_data.optional_labels_bits));
847 }
848 }
849
850 // OpenTelemetry calls our callback with its observable_registry's lock held.
851 template <typename ValueType>
CallbackGaugeCallback(opentelemetry::metrics::ObserverResult result,void * arg)852 void OpenTelemetryPlugin::CallbackGaugeState<ValueType>::CallbackGaugeCallback(
853 opentelemetry::metrics::ObserverResult result, void* arg) {
854 auto* callback_gauge_state = static_cast<CallbackGaugeState<ValueType>*>(arg);
855 auto now = grpc_core::Timestamp::Now();
856 grpc_core::MutexLock plugin_lock(&callback_gauge_state->ot_plugin->mu_);
857 for (auto& elem : callback_gauge_state->caches) {
858 auto* registered_metric_callback = elem.first;
859 auto iter = callback_gauge_state->ot_plugin->callback_timestamps_.find(
860 registered_metric_callback);
861 GPR_ASSERT(iter !=
862 callback_gauge_state->ot_plugin->callback_timestamps_.end());
863 if (now - iter->second < registered_metric_callback->min_interval()) {
864 // Use cached value.
865 callback_gauge_state->Observe(result, elem.second);
866 continue;
867 }
868 // Otherwise update and use the cache.
869 iter->second = now;
870 CallbackMetricReporter reporter(callback_gauge_state->ot_plugin,
871 registered_metric_callback);
872 registered_metric_callback->Run(reporter);
873 callback_gauge_state->Observe(result, elem.second);
874 }
875 }
876
GetClientCallTracer(const grpc_core::Slice & path,bool registered_method,std::shared_ptr<grpc_core::StatsPlugin::ScopeConfig> scope_config)877 grpc_core::ClientCallTracer* OpenTelemetryPlugin::GetClientCallTracer(
878 const grpc_core::Slice& path, bool registered_method,
879 std::shared_ptr<grpc_core::StatsPlugin::ScopeConfig> scope_config) {
880 return grpc_core::GetContext<grpc_core::Arena>()
881 ->ManagedNew<ClientCallTracer>(
882 path, grpc_core::GetContext<grpc_core::Arena>(), registered_method,
883 this,
884 std::static_pointer_cast<OpenTelemetryPlugin::ClientScopeConfig>(
885 scope_config));
886 }
887
GetServerCallTracer(std::shared_ptr<grpc_core::StatsPlugin::ScopeConfig> scope_config)888 grpc_core::ServerCallTracer* OpenTelemetryPlugin::GetServerCallTracer(
889 std::shared_ptr<grpc_core::StatsPlugin::ScopeConfig> scope_config) {
890 return grpc_core::GetContext<grpc_core::Arena>()
891 ->ManagedNew<ServerCallTracer>(
892 this,
893 std::static_pointer_cast<OpenTelemetryPlugin::ServerScopeConfig>(
894 scope_config));
895 }
896
897 } // namespace internal
898
899 constexpr absl::string_view
900 OpenTelemetryPluginBuilder::kClientAttemptStartedInstrumentName;
901 constexpr absl::string_view
902 OpenTelemetryPluginBuilder::kClientAttemptDurationInstrumentName;
903 constexpr absl::string_view OpenTelemetryPluginBuilder::
904 kClientAttemptSentTotalCompressedMessageSizeInstrumentName;
905 constexpr absl::string_view OpenTelemetryPluginBuilder::
906 kClientAttemptRcvdTotalCompressedMessageSizeInstrumentName;
907 constexpr absl::string_view
908 OpenTelemetryPluginBuilder::kServerCallStartedInstrumentName;
909 constexpr absl::string_view
910 OpenTelemetryPluginBuilder::kServerCallDurationInstrumentName;
911 constexpr absl::string_view OpenTelemetryPluginBuilder::
912 kServerCallSentTotalCompressedMessageSizeInstrumentName;
913 constexpr absl::string_view OpenTelemetryPluginBuilder::
914 kServerCallRcvdTotalCompressedMessageSizeInstrumentName;
915
916 //
917 // OpenTelemetryPluginBuilder
918 //
919
OpenTelemetryPluginBuilder()920 OpenTelemetryPluginBuilder::OpenTelemetryPluginBuilder()
921 : impl_(std::make_unique<internal::OpenTelemetryPluginBuilderImpl>()) {}
922
923 OpenTelemetryPluginBuilder::~OpenTelemetryPluginBuilder() = default;
924
SetMeterProvider(std::shared_ptr<opentelemetry::metrics::MeterProvider> meter_provider)925 OpenTelemetryPluginBuilder& OpenTelemetryPluginBuilder::SetMeterProvider(
926 std::shared_ptr<opentelemetry::metrics::MeterProvider> meter_provider) {
927 impl_->SetMeterProvider(std::move(meter_provider));
928 return *this;
929 }
930
931 OpenTelemetryPluginBuilder&
SetTargetAttributeFilter(absl::AnyInvocable<bool (absl::string_view)const> target_attribute_filter)932 OpenTelemetryPluginBuilder::SetTargetAttributeFilter(
933 absl::AnyInvocable<bool(absl::string_view /*target*/) const>
934 target_attribute_filter) {
935 impl_->SetTargetAttributeFilter(std::move(target_attribute_filter));
936 return *this;
937 }
938
939 OpenTelemetryPluginBuilder&
SetGenericMethodAttributeFilter(absl::AnyInvocable<bool (absl::string_view)const> generic_method_attribute_filter)940 OpenTelemetryPluginBuilder::SetGenericMethodAttributeFilter(
941 absl::AnyInvocable<bool(absl::string_view /*generic_method*/) const>
942 generic_method_attribute_filter) {
943 impl_->SetGenericMethodAttributeFilter(
944 std::move(generic_method_attribute_filter));
945 return *this;
946 }
947
EnableMetrics(absl::Span<const absl::string_view> metric_names)948 OpenTelemetryPluginBuilder& OpenTelemetryPluginBuilder::EnableMetrics(
949 absl::Span<const absl::string_view> metric_names) {
950 impl_->EnableMetrics(metric_names);
951 return *this;
952 }
953
DisableMetrics(absl::Span<const absl::string_view> metric_names)954 OpenTelemetryPluginBuilder& OpenTelemetryPluginBuilder::DisableMetrics(
955 absl::Span<const absl::string_view> metric_names) {
956 impl_->DisableMetrics(metric_names);
957 return *this;
958 }
959
DisableAllMetrics()960 OpenTelemetryPluginBuilder& OpenTelemetryPluginBuilder::DisableAllMetrics() {
961 impl_->DisableAllMetrics();
962 return *this;
963 }
964
AddPluginOption(std::unique_ptr<OpenTelemetryPluginOption> option)965 OpenTelemetryPluginBuilder& OpenTelemetryPluginBuilder::AddPluginOption(
966 std::unique_ptr<OpenTelemetryPluginOption> option) {
967 impl_->AddPluginOption(
968 std::unique_ptr<grpc::internal::InternalOpenTelemetryPluginOption>(
969 static_cast<grpc::internal::InternalOpenTelemetryPluginOption*>(
970 option.release())));
971 return *this;
972 }
973
AddOptionalLabel(absl::string_view optional_label_key)974 OpenTelemetryPluginBuilder& OpenTelemetryPluginBuilder::AddOptionalLabel(
975 absl::string_view optional_label_key) {
976 impl_->AddOptionalLabel(optional_label_key);
977 return *this;
978 }
979
SetChannelScopeFilter(absl::AnyInvocable<bool (const ChannelScope &)const> channel_scope_filter)980 OpenTelemetryPluginBuilder& OpenTelemetryPluginBuilder::SetChannelScopeFilter(
981 absl::AnyInvocable<bool(const ChannelScope& /*scope*/) const>
982 channel_scope_filter) {
983 impl_->SetChannelScopeFilter(std::move(channel_scope_filter));
984 return *this;
985 }
986
BuildAndRegisterGlobal()987 absl::Status OpenTelemetryPluginBuilder::BuildAndRegisterGlobal() {
988 return impl_->BuildAndRegisterGlobal();
989 }
990
991 } // namespace grpc
992