• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/cpp/ext/csm/csm_observability.h"
20 
21 #include <grpc/support/port_platform.h>
22 #include <grpcpp/ext/csm_observability.h>
23 
24 #include <memory>
25 #include <string>
26 #include <utility>
27 
28 #include "absl/functional/any_invocable.h"
29 #include "absl/log/log.h"
30 #include "absl/status/statusor.h"
31 #include "absl/types/optional.h"
32 #include "google/cloud/opentelemetry/resource_detector.h"
33 #include "opentelemetry/sdk/metrics/meter_provider.h"
34 #include "opentelemetry/sdk/resource/resource.h"
35 #include "opentelemetry/sdk/resource/resource_detector.h"
36 #include "src/core/lib/channel/channel_args.h"
37 #include "src/core/util/uri.h"
38 #include "src/core/xds/grpc/xds_enabled_server.h"
39 #include "src/cpp/ext/csm/metadata_exchange.h"
40 #include "src/cpp/ext/otel/otel_plugin.h"
41 
42 namespace grpc {
43 
44 namespace internal {
45 
46 namespace {
47 std::atomic<bool> g_csm_plugin_enabled(false);
48 }
49 
CsmServerSelector(const grpc_core::ChannelArgs &)50 bool CsmServerSelector(const grpc_core::ChannelArgs& /*args*/) {
51   return g_csm_plugin_enabled;
52 }
53 
CsmChannelTargetSelector(absl::string_view target)54 bool CsmChannelTargetSelector(absl::string_view target) {
55   if (!g_csm_plugin_enabled) return false;
56   auto uri = grpc_core::URI::Parse(target);
57   if (!uri.ok()) {
58     LOG(ERROR) << "Failed to parse URI: " << target;
59     return false;
60   }
61   // CSM channels should have an "xds" scheme
62   if (uri->scheme() != "xds") {
63     return false;
64   }
65   // If set, the authority should be TD
66   if (!uri->authority().empty() &&
67       uri->authority() != "traffic-director-global.xds.googleapis.com") {
68     return false;
69   }
70   return true;
71 }
72 
73 class CsmOpenTelemetryPluginOption
74     : public grpc::internal::InternalOpenTelemetryPluginOption {
75  public:
CsmOpenTelemetryPluginOption()76   CsmOpenTelemetryPluginOption()
77       : labels_injector_(std::make_unique<internal::ServiceMeshLabelsInjector>(
78             google::cloud::otel::MakeResourceDetector()
79                 ->Detect()
80                 .GetAttributes())) {}
81 
IsActiveOnClientChannel(absl::string_view target) const82   bool IsActiveOnClientChannel(absl::string_view target) const override {
83     return CsmChannelTargetSelector(target);
84   }
85 
IsActiveOnServer(const grpc_core::ChannelArgs & args) const86   bool IsActiveOnServer(const grpc_core::ChannelArgs& args) const override {
87     return CsmServerSelector(args);
88   }
89 
labels_injector() const90   const grpc::internal::LabelsInjector* labels_injector() const override {
91     return labels_injector_.get();
92   }
93 
94  private:
95   std::unique_ptr<internal::ServiceMeshLabelsInjector> labels_injector_;
96 };
97 
98 }  // namespace internal
99 
100 //
101 // CsmObservability
102 //
103 
~CsmObservability()104 CsmObservability::~CsmObservability() {
105   if (valid_) {
106     internal::g_csm_plugin_enabled = false;
107   }
108 }
109 
CsmObservability(CsmObservability && other)110 CsmObservability::CsmObservability(CsmObservability&& other) noexcept {
111   other.valid_ = false;
112 }
operator =(CsmObservability && other)113 CsmObservability& CsmObservability::operator=(
114     CsmObservability&& other) noexcept {
115   other.valid_ = false;
116   return *this;
117 }
118 
119 //
120 // CsmObservabilityBuilder
121 //
122 
CsmObservabilityBuilder()123 CsmObservabilityBuilder::CsmObservabilityBuilder()
124     : builder_(
125           std::make_unique<grpc::internal::OpenTelemetryPluginBuilderImpl>()) {}
126 
127 CsmObservabilityBuilder::~CsmObservabilityBuilder() = default;
128 
SetMeterProvider(std::shared_ptr<opentelemetry::metrics::MeterProvider> meter_provider)129 CsmObservabilityBuilder& CsmObservabilityBuilder::SetMeterProvider(
130     std::shared_ptr<opentelemetry::metrics::MeterProvider> meter_provider) {
131   builder_->SetMeterProvider(meter_provider);
132   return *this;
133 }
134 
SetTargetAttributeFilter(absl::AnyInvocable<bool (absl::string_view)const> target_attribute_filter)135 CsmObservabilityBuilder& CsmObservabilityBuilder::SetTargetAttributeFilter(
136     absl::AnyInvocable<bool(absl::string_view /*target*/) const>
137         target_attribute_filter) {
138   builder_->SetTargetAttributeFilter(std::move(target_attribute_filter));
139   return *this;
140 }
141 
142 CsmObservabilityBuilder&
SetGenericMethodAttributeFilter(absl::AnyInvocable<bool (absl::string_view)const> generic_method_attribute_filter)143 CsmObservabilityBuilder::SetGenericMethodAttributeFilter(
144     absl::AnyInvocable<bool(absl::string_view /*generic_method*/) const>
145         generic_method_attribute_filter) {
146   builder_->SetGenericMethodAttributeFilter(
147       std::move(generic_method_attribute_filter));
148   return *this;
149 }
150 
BuildAndRegister()151 absl::StatusOr<CsmObservability> CsmObservabilityBuilder::BuildAndRegister() {
152   builder_->AddPluginOption(
153       std::make_unique<grpc::internal::CsmOpenTelemetryPluginOption>());
154   auto status = builder_->BuildAndRegisterGlobal();
155   internal::g_csm_plugin_enabled = true;
156   if (!status.ok()) {
157     return status;
158   }
159   return CsmObservability();
160 }
161 
162 }  // namespace grpc
163