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 &)50bool CsmServerSelector(const grpc_core::ChannelArgs& /*args*/) { 51 return g_csm_plugin_enabled; 52 } 53 CsmChannelTargetSelector(absl::string_view target)54bool 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()104CsmObservability::~CsmObservability() { 105 if (valid_) { 106 internal::g_csm_plugin_enabled = false; 107 } 108 } 109 CsmObservability(CsmObservability && other)110CsmObservability::CsmObservability(CsmObservability&& other) noexcept { 111 other.valid_ = false; 112 } operator =(CsmObservability && other)113CsmObservability& CsmObservability::operator=( 114 CsmObservability&& other) noexcept { 115 other.valid_ = false; 116 return *this; 117 } 118 119 // 120 // CsmObservabilityBuilder 121 // 122 CsmObservabilityBuilder()123CsmObservabilityBuilder::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)129CsmObservabilityBuilder& 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)135CsmObservabilityBuilder& 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)143CsmObservabilityBuilder::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()151absl::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