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