• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2024 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 "metadata_exchange.h"
20 
21 #include <grpc/slice.h>
22 #include <stddef.h>
23 
24 #include <algorithm>
25 #include <array>
26 #include <cstdint>
27 #include <unordered_map>
28 
29 #include "absl/strings/string_view.h"
30 #include "constants.h"
31 #include "src/core/telemetry/call_tracer.h"
32 
33 namespace grpc_observability {
34 
PythonLabelsInjector(const std::vector<Label> & exchange_labels)35 PythonLabelsInjector::PythonLabelsInjector(
36     const std::vector<Label>& exchange_labels) {
37   for (const auto& label : exchange_labels) {
38     auto it = MetadataExchangeKeyNames.find(label.key);
39     if (it != MetadataExchangeKeyNames.end()) {
40       metadata_to_exchange_.emplace_back(label.key, label.value);
41     }
42   }
43 }
44 
GetExchangeLabels(grpc_metadata_batch * incoming_initial_metadata) const45 std::vector<Label> PythonLabelsInjector::GetExchangeLabels(
46     grpc_metadata_batch* incoming_initial_metadata) const {
47   std::vector<Label> labels;
48   for (const auto& key : MetadataExchangeKeyNames) {
49     if (key == kXEnvoyPeerMetadata) {
50       auto xds_peer_metadata =
51           incoming_initial_metadata->Take(grpc_core::XEnvoyPeerMetadata());
52       grpc_core::Slice xds_remote_metadata = xds_peer_metadata.has_value()
53                                                  ? *std::move(xds_peer_metadata)
54                                                  : grpc_core::Slice();
55       if (!xds_remote_metadata.empty()) {
56         std::string xds_decoded_metadata;
57         bool metadata_decoded = absl::Base64Unescape(
58             xds_remote_metadata.as_string_view(), &xds_decoded_metadata);
59         if (metadata_decoded) {
60           labels.emplace_back(kXEnvoyPeerMetadata, xds_decoded_metadata);
61         }
62       }
63     }
64   }
65   return labels;
66 }
67 
AddExchangeLabelsToMetadata(grpc_metadata_batch * outgoing_initial_metadata) const68 void PythonLabelsInjector::AddExchangeLabelsToMetadata(
69     grpc_metadata_batch* outgoing_initial_metadata) const {
70   for (const auto& metadata : metadata_to_exchange_) {
71     if (metadata.first == kXEnvoyPeerMetadata) {
72       grpc_core::Slice metadata_slice = grpc_core::Slice::FromCopiedString(
73           absl::Base64Escape(absl::string_view(metadata.second)));
74       outgoing_initial_metadata->Set(grpc_core::XEnvoyPeerMetadata(),
75                                      metadata_slice.Ref());
76     }
77   }
78 }
79 
AddXdsOptionalLabels(bool is_client,absl::Span<const grpc_core::RefCountedStringValue> optional_labels_span,std::vector<Label> & labels)80 void PythonLabelsInjector::AddXdsOptionalLabels(
81     bool is_client,
82     absl::Span<const grpc_core::RefCountedStringValue> optional_labels_span,
83     std::vector<Label>& labels) {
84   if (!is_client) {
85     // Currently the CSM optional labels are only set on client.
86     return;
87   }
88   // Performs JSON label name format to CSM Observability Metric spec format
89   // conversion.
90   absl::string_view service_name =
91       optional_labels_span[static_cast<size_t>(
92                                grpc_core::ClientCallTracer::CallAttemptTracer::
93                                    OptionalLabelKey::kXdsServiceName)]
94           .as_string_view();
95   absl::string_view service_namespace =
96       optional_labels_span[static_cast<size_t>(
97                                grpc_core::ClientCallTracer::CallAttemptTracer::
98                                    OptionalLabelKey::kXdsServiceNamespace)]
99           .as_string_view();
100   // According to the CSM Observability Metric spec, if the control plane fails
101   // to provide these labels, the client will set their values to "unknown".
102   if (service_name.empty()) {
103     service_name = "unknown";
104   }
105   if (service_namespace.empty()) {
106     service_namespace = "unknown";
107   }
108   labels.emplace_back("csm.service_name", std::string(service_name));
109   labels.emplace_back("csm.service_namespace_name",
110                       std::string(service_namespace));
111 }
112 
113 }  // namespace grpc_observability
114