xref: /aosp_15_r20/external/grpc-grpc/src/cpp/ext/otel/key_value_iterable.h (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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 #ifndef GRPC_SRC_CPP_EXT_OTEL_KEY_VALUE_ITERABLE_H
20 #define GRPC_SRC_CPP_EXT_OTEL_KEY_VALUE_ITERABLE_H
21 
22 #include <grpc/support/port_platform.h>
23 
24 #include <stddef.h>
25 
26 #include <utility>
27 
28 #include "absl/strings/string_view.h"
29 #include "absl/types/optional.h"
30 #include "absl/types/span.h"
31 #include "opentelemetry/common/attribute_value.h"
32 #include "opentelemetry/common/key_value_iterable.h"
33 #include "opentelemetry/nostd/function_ref.h"
34 #include "opentelemetry/nostd/string_view.h"
35 
36 #include "src/cpp/ext/otel/otel_plugin.h"
37 
38 namespace grpc {
39 namespace internal {
40 
AbslStrViewToOpenTelemetryStrView(absl::string_view str)41 inline opentelemetry::nostd::string_view AbslStrViewToOpenTelemetryStrView(
42     absl::string_view str) {
43   return opentelemetry::nostd::string_view(str.data(), str.size());
44 }
45 
46 // An iterable class based on opentelemetry::common::KeyValueIterable that
47 // allows gRPC to iterate on its various sources of attributes and avoid an
48 // allocation in cases wherever possible.
49 class OpenTelemetryPlugin::KeyValueIterable
50     : public opentelemetry::common::KeyValueIterable {
51  public:
KeyValueIterable(const std::vector<std::unique_ptr<LabelsIterable>> & injected_labels_from_plugin_options,absl::Span<const std::pair<absl::string_view,absl::string_view>> additional_labels,const OpenTelemetryPlugin::ActivePluginOptionsView * active_plugin_options_view,absl::Span<const grpc_core::RefCountedStringValue> optional_labels,bool is_client,const OpenTelemetryPlugin * otel_plugin)52   KeyValueIterable(
53       const std::vector<std::unique_ptr<LabelsIterable>>&
54           injected_labels_from_plugin_options,
55       absl::Span<const std::pair<absl::string_view, absl::string_view>>
56           additional_labels,
57       const OpenTelemetryPlugin::ActivePluginOptionsView*
58           active_plugin_options_view,
59       absl::Span<const grpc_core::RefCountedStringValue> optional_labels,
60       bool is_client, const OpenTelemetryPlugin* otel_plugin)
61       : injected_labels_from_plugin_options_(
62             injected_labels_from_plugin_options),
63         additional_labels_(additional_labels),
64         active_plugin_options_view_(active_plugin_options_view),
65         optional_labels_(optional_labels),
66         is_client_(is_client),
67         otel_plugin_(otel_plugin) {}
68 
ForEachKeyValue(opentelemetry::nostd::function_ref<bool (opentelemetry::nostd::string_view,opentelemetry::common::AttributeValue)> callback)69   bool ForEachKeyValue(opentelemetry::nostd::function_ref<
70                        bool(opentelemetry::nostd::string_view,
71                             opentelemetry::common::AttributeValue)>
72                            callback) const noexcept override {
73     if (active_plugin_options_view_ != nullptr &&
74         !active_plugin_options_view_->ForEach(
75             [callback, this](
76                 const InternalOpenTelemetryPluginOption& plugin_option,
77                 size_t /*index*/) {
78               return plugin_option.labels_injector()->AddOptionalLabels(
79                   is_client_, optional_labels_, callback);
80             },
81             otel_plugin_)) {
82       return false;
83     }
84     for (const auto& plugin_option_injected_iterable :
85          injected_labels_from_plugin_options_) {
86       if (plugin_option_injected_iterable != nullptr) {
87         plugin_option_injected_iterable->ResetIteratorPosition();
88         while (const auto& pair = plugin_option_injected_iterable->Next()) {
89           if (!callback(AbslStrViewToOpenTelemetryStrView(pair->first),
90                         AbslStrViewToOpenTelemetryStrView(pair->second))) {
91             return false;
92           }
93         }
94       }
95     }
96     for (const auto& pair : additional_labels_) {
97       if (!callback(AbslStrViewToOpenTelemetryStrView(pair.first),
98                     AbslStrViewToOpenTelemetryStrView(pair.second))) {
99         return false;
100       }
101     }
102     // Add per-call optional labels
103     if (!optional_labels_.empty()) {
104       GPR_ASSERT(
105           optional_labels_.size() ==
106           static_cast<size_t>(grpc_core::ClientCallTracer::CallAttemptTracer::
107                                   OptionalLabelKey::kSize));
108       for (size_t i = 0; i < optional_labels_.size(); ++i) {
109         if (!otel_plugin_->per_call_optional_label_bits_.test(i)) {
110           continue;
111         }
112         if (!callback(
113                 AbslStrViewToOpenTelemetryStrView(OptionalLabelKeyToString(
114                     static_cast<grpc_core::ClientCallTracer::CallAttemptTracer::
115                                     OptionalLabelKey>(i))),
116                 AbslStrViewToOpenTelemetryStrView(
117                     optional_labels_[i].as_string_view()))) {
118           return false;
119         }
120       }
121     }
122     return true;
123   }
124 
size()125   size_t size() const noexcept override {
126     size_t size = 0;
127     for (const auto& plugin_option_injected_iterable :
128          injected_labels_from_plugin_options_) {
129       if (plugin_option_injected_iterable != nullptr) {
130         size += plugin_option_injected_iterable->Size();
131       }
132     }
133     size += additional_labels_.size();
134     if (active_plugin_options_view_ != nullptr) {
135       active_plugin_options_view_->ForEach(
136           [&size, this](const InternalOpenTelemetryPluginOption& plugin_option,
137                         size_t /*index*/) {
138             size += plugin_option.labels_injector()->GetOptionalLabelsSize(
139                 is_client_, optional_labels_);
140             return true;
141           },
142           otel_plugin_);
143     }
144     return size;
145   }
146 
147  private:
148   const std::vector<std::unique_ptr<LabelsIterable>>&
149       injected_labels_from_plugin_options_;
150   absl::Span<const std::pair<absl::string_view, absl::string_view>>
151       additional_labels_;
152   const OpenTelemetryPlugin::ActivePluginOptionsView*
153       active_plugin_options_view_;
154   absl::Span<const grpc_core::RefCountedStringValue> optional_labels_;
155   bool is_client_;
156   const OpenTelemetryPlugin* otel_plugin_;
157 };
158 
159 }  // namespace internal
160 }  // namespace grpc
161 
162 #endif  // GRPC_SRC_CPP_EXT_OTEL_KEY_VALUE_ITERABLE_H
163