LCOV - code coverage report
Current view: top level - source/extensions/tracers/opencensus - opencensus_tracer_impl.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 234 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 17 0.0 %

          Line data    Source code
       1             : #include "source/extensions/tracers/opencensus/opencensus_tracer_impl.h"
       2             : 
       3             : #include <grpcpp/grpcpp.h>
       4             : 
       5             : #include "envoy/config/trace/v3/opencensus.pb.h"
       6             : #include "envoy/http/header_map.h"
       7             : 
       8             : #include "source/common/common/base64.h"
       9             : #include "source/common/common/empty_string.h"
      10             : #include "source/common/tracing/trace_context_impl.h"
      11             : 
      12             : #include "absl/strings/str_cat.h"
      13             : #include "google/devtools/cloudtrace/v2/tracing.grpc.pb.h"
      14             : #include "opencensus/exporters/trace/ocagent/ocagent_exporter.h"
      15             : #include "opencensus/exporters/trace/stackdriver/stackdriver_exporter.h"
      16             : #include "opencensus/exporters/trace/stdout/stdout_exporter.h"
      17             : #include "opencensus/exporters/trace/zipkin/zipkin_exporter.h"
      18             : #include "opencensus/trace/propagation/b3.h"
      19             : #include "opencensus/trace/propagation/cloud_trace_context.h"
      20             : #include "opencensus/trace/propagation/grpc_trace_bin.h"
      21             : #include "opencensus/trace/propagation/trace_context.h"
      22             : #include "opencensus/trace/sampler.h"
      23             : #include "opencensus/trace/span.h"
      24             : #include "opencensus/trace/span_context.h"
      25             : #include "opencensus/trace/trace_config.h"
      26             : #include "opencensus/trace/trace_params.h"
      27             : 
      28             : #ifdef ENVOY_GOOGLE_GRPC
      29             : #include "source/common/grpc/google_grpc_utils.h"
      30             : #endif
      31             : 
      32             : namespace Envoy {
      33             : namespace Extensions {
      34             : namespace Tracers {
      35             : namespace OpenCensus {
      36             : 
      37             : #ifdef ENVOY_GOOGLE_GRPC
      38             : constexpr char GoogleStackdriverTraceAddress[] = "cloudtrace.googleapis.com";
      39             : #endif
      40             : 
      41             : namespace {
      42             : 
      43             : class ConstantValues {
      44             : public:
      45             :   const Tracing::TraceContextHandler TRACEPARENT{"traceparent"};
      46             :   const Tracing::TraceContextHandler GRPC_TRACE_BIN{"grpc-trace-bin"};
      47             :   const Tracing::TraceContextHandler X_CLOUD_TRACE_CONTEXT{"x-cloud-trace-context"};
      48             :   const Tracing::TraceContextHandler X_B3_TRACEID{"x-b3-traceid"};
      49             :   const Tracing::TraceContextHandler X_B3_SPANID{"x-b3-spanid"};
      50             :   const Tracing::TraceContextHandler X_B3_SAMPLED{"x-b3-sampled"};
      51             :   const Tracing::TraceContextHandler X_B3_FLAGS{"x-b3-flags"};
      52             : };
      53             : 
      54             : using Constants = ConstSingleton<ConstantValues>;
      55             : 
      56             : /**
      57             :  * OpenCensus tracing implementation of the Envoy Span object.
      58             :  */
      59             : class Span : public Tracing::Span {
      60             : public:
      61             :   Span(const Tracing::Config& config, const envoy::config::trace::v3::OpenCensusConfig& oc_config,
      62             :        Tracing::TraceContext& trace_context, const std::string& operation_name,
      63             :        SystemTime start_time, const Tracing::Decision tracing_decision);
      64             : 
      65             :   // Used by spawnChild().
      66             :   Span(const envoy::config::trace::v3::OpenCensusConfig& oc_config,
      67             :        ::opencensus::trace::Span&& span);
      68             : 
      69             :   void setOperation(absl::string_view operation) override;
      70             :   void setTag(absl::string_view name, absl::string_view value) override;
      71             :   void log(SystemTime timestamp, const std::string& event) override;
      72             :   void finishSpan() override;
      73             :   void injectContext(Tracing::TraceContext& trace_context,
      74             :                      const Upstream::HostDescriptionConstSharedPtr&) override;
      75             :   Tracing::SpanPtr spawnChild(const Tracing::Config& config, const std::string& name,
      76             :                               SystemTime start_time) override;
      77             :   void setSampled(bool sampled) override;
      78             : 
      79             :   // OpenCensus doesn't support baggage, so noop these OpenTracing functions.
      80           0 :   void setBaggage(absl::string_view, absl::string_view) override{};
      81           0 :   std::string getBaggage(absl::string_view) override { return EMPTY_STRING; };
      82             : 
      83             :   std::string getTraceIdAsHex() const override;
      84             : 
      85             : private:
      86             :   ::opencensus::trace::Span span_;
      87             :   const envoy::config::trace::v3::OpenCensusConfig& oc_config_;
      88             : };
      89             : 
      90             : ::opencensus::trace::Span
      91             : startSpanHelper(const std::string& name, bool traced, const Tracing::TraceContext& trace_context,
      92           0 :                 const envoy::config::trace::v3::OpenCensusConfig& oc_config) {
      93             :   // Determine if there is a parent context.
      94           0 :   using OpenCensusConfig = envoy::config::trace::v3::OpenCensusConfig;
      95           0 :   ::opencensus::trace::SpanContext parent_ctx;
      96           0 :   for (const auto& incoming : oc_config.incoming_trace_context()) {
      97           0 :     bool found = false;
      98           0 :     switch (incoming) {
      99           0 :     case OpenCensusConfig::TRACE_CONTEXT: {
     100           0 :       const auto entry = Constants::get().TRACEPARENT.get(trace_context);
     101           0 :       if (entry.has_value()) {
     102           0 :         found = true;
     103             :         // This is an implicitly untrusted header, so only the first value is used.
     104           0 :         parent_ctx = ::opencensus::trace::propagation::FromTraceParentHeader(entry.value());
     105           0 :       }
     106           0 :       break;
     107           0 :     }
     108           0 :     case OpenCensusConfig::GRPC_TRACE_BIN: {
     109           0 :       const auto entry = Constants::get().GRPC_TRACE_BIN.get(trace_context);
     110           0 :       if (entry.has_value()) {
     111           0 :         found = true;
     112             :         // This is an implicitly untrusted header, so only the first value is used.
     113           0 :         parent_ctx = ::opencensus::trace::propagation::FromGrpcTraceBinHeader(
     114           0 :             Base64::decodeWithoutPadding(entry.value()));
     115           0 :       }
     116           0 :       break;
     117           0 :     }
     118           0 :     case OpenCensusConfig::CLOUD_TRACE_CONTEXT: {
     119           0 :       const auto entry = Constants::get().X_CLOUD_TRACE_CONTEXT.get(trace_context);
     120           0 :       if (entry.has_value()) {
     121           0 :         found = true;
     122             :         // This is an implicitly untrusted header, so only the first value is used.
     123           0 :         parent_ctx = ::opencensus::trace::propagation::FromCloudTraceContextHeader(entry.value());
     124           0 :       }
     125           0 :       break;
     126           0 :     }
     127             : 
     128           0 :     case OpenCensusConfig::B3: {
     129           0 :       absl::string_view b3_trace_id;
     130           0 :       absl::string_view b3_span_id;
     131           0 :       absl::string_view b3_sampled;
     132           0 :       absl::string_view b3_flags;
     133           0 :       const auto h_b3_trace_id = Constants::get().X_B3_TRACEID.get(trace_context);
     134           0 :       if (h_b3_trace_id.has_value()) {
     135           0 :         b3_trace_id = h_b3_trace_id.value();
     136           0 :       }
     137           0 :       const auto h_b3_span_id = Constants::get().X_B3_SPANID.get(trace_context);
     138           0 :       if (h_b3_span_id.has_value()) {
     139           0 :         b3_span_id = h_b3_span_id.value();
     140           0 :       }
     141           0 :       const auto h_b3_sampled = Constants::get().X_B3_SAMPLED.get(trace_context);
     142           0 :       if (h_b3_sampled.has_value()) {
     143           0 :         b3_sampled = h_b3_sampled.value();
     144           0 :       }
     145           0 :       const auto h_b3_flags = Constants::get().X_B3_FLAGS.get(trace_context);
     146           0 :       if (h_b3_flags.has_value()) {
     147           0 :         b3_flags = h_b3_flags.value();
     148           0 :       }
     149           0 :       if (h_b3_trace_id.has_value() && h_b3_span_id.has_value()) {
     150           0 :         found = true;
     151           0 :         parent_ctx = ::opencensus::trace::propagation::FromB3Headers(b3_trace_id, b3_span_id,
     152           0 :                                                                      b3_sampled, b3_flags);
     153           0 :       }
     154           0 :       break;
     155           0 :     }
     156           0 :     }
     157             :     // First header found wins.
     158           0 :     if (found) {
     159           0 :       break;
     160           0 :     }
     161           0 :   }
     162             : 
     163             :   // Honor Envoy's tracing decision.
     164           0 :   ::opencensus::trace::AlwaysSampler always_sampler;
     165           0 :   ::opencensus::trace::NeverSampler never_sampler;
     166             :   // This is safe because opts are not used after StartSpan.
     167           0 :   ::opencensus::trace::StartSpanOptions opts{&never_sampler};
     168           0 :   if (traced) {
     169           0 :     opts.sampler = &always_sampler;
     170           0 :   }
     171             : 
     172           0 :   if (parent_ctx.IsValid()) {
     173           0 :     return ::opencensus::trace::Span::StartSpanWithRemoteParent(name, parent_ctx, opts);
     174           0 :   }
     175           0 :   return ::opencensus::trace::Span::StartSpan(name, /*parent=*/nullptr, opts);
     176           0 : }
     177             : 
     178             : Span::Span(const Tracing::Config& config,
     179             :            const envoy::config::trace::v3::OpenCensusConfig& oc_config,
     180             :            Tracing::TraceContext& trace_context, const std::string& operation_name,
     181             :            SystemTime /*start_time*/, const Tracing::Decision tracing_decision)
     182             :     : span_(startSpanHelper(operation_name, tracing_decision.traced, trace_context, oc_config)),
     183           0 :       oc_config_(oc_config) {
     184           0 :   span_.AddAttribute("OperationName", config.operationName() == Tracing::OperationName::Ingress
     185           0 :                                           ? "Ingress"
     186           0 :                                           : "Egress");
     187           0 : }
     188             : 
     189             : Span::Span(const envoy::config::trace::v3::OpenCensusConfig& oc_config,
     190             :            ::opencensus::trace::Span&& span)
     191           0 :     : span_(std::move(span)), oc_config_(oc_config) {}
     192             : 
     193           0 : void Span::setOperation(absl::string_view operation) { span_.SetName(operation); }
     194             : 
     195           0 : void Span::setTag(absl::string_view name, absl::string_view value) {
     196           0 :   span_.AddAttribute(name, value);
     197           0 : }
     198             : 
     199           0 : void Span::log(SystemTime /*timestamp*/, const std::string& event) {
     200             :   // timestamp is ignored.
     201           0 :   span_.AddAnnotation(event);
     202           0 : }
     203             : 
     204           0 : void Span::finishSpan() { span_.End(); }
     205             : 
     206             : void Span::injectContext(Tracing::TraceContext& trace_context,
     207           0 :                          const Upstream::HostDescriptionConstSharedPtr&) {
     208           0 :   using OpenCensusConfig = envoy::config::trace::v3::OpenCensusConfig;
     209           0 :   const auto& ctx = span_.context();
     210           0 :   for (const auto& outgoing : oc_config_.outgoing_trace_context()) {
     211           0 :     switch (outgoing) {
     212           0 :     case OpenCensusConfig::TRACE_CONTEXT:
     213           0 :       Constants::get().TRACEPARENT.setRefKey(
     214           0 :           trace_context, ::opencensus::trace::propagation::ToTraceParentHeader(ctx));
     215           0 :       break;
     216           0 :     case OpenCensusConfig::GRPC_TRACE_BIN: {
     217           0 :       std::string val = ::opencensus::trace::propagation::ToGrpcTraceBinHeader(ctx);
     218           0 :       val = Base64::encode(val.data(), val.size(), /*add_padding=*/false);
     219           0 :       Constants::get().GRPC_TRACE_BIN.setRefKey(trace_context, val);
     220           0 :       break;
     221           0 :     }
     222           0 :     case OpenCensusConfig::CLOUD_TRACE_CONTEXT:
     223           0 :       Constants::get().X_CLOUD_TRACE_CONTEXT.setRefKey(
     224           0 :           trace_context, ::opencensus::trace::propagation::ToCloudTraceContextHeader(ctx));
     225           0 :       break;
     226           0 :     case OpenCensusConfig::B3:
     227           0 :       Constants::get().X_B3_TRACEID.setRefKey(
     228           0 :           trace_context, ::opencensus::trace::propagation::ToB3TraceIdHeader(ctx));
     229           0 :       Constants::get().X_B3_SPANID.setRefKey(
     230           0 :           trace_context, ::opencensus::trace::propagation::ToB3SpanIdHeader(ctx));
     231           0 :       Constants::get().X_B3_SAMPLED.setRefKey(
     232           0 :           trace_context, ::opencensus::trace::propagation::ToB3SampledHeader(ctx));
     233             :       // OpenCensus's trace context propagation doesn't produce the
     234             :       // "X-B3-Flags:" header.
     235           0 :       break;
     236           0 :     }
     237           0 :   }
     238           0 : }
     239             : 
     240           0 : std::string Span::getTraceIdAsHex() const {
     241           0 :   const auto& ctx = span_.context();
     242           0 :   return ctx.trace_id().ToHex();
     243           0 : }
     244             : 
     245             : Tracing::SpanPtr Span::spawnChild(const Tracing::Config& /*config*/, const std::string& name,
     246           0 :                                   SystemTime /*start_time*/) {
     247           0 :   return std::make_unique<Span>(oc_config_,
     248           0 :                                 ::opencensus::trace::Span::StartSpan(name, /*parent=*/&span_));
     249           0 : }
     250             : 
     251           0 : void Span::setSampled(bool sampled) { span_.AddAnnotation("setSampled", {{"sampled", sampled}}); }
     252             : 
     253             : } // namespace
     254             : 
     255             : Driver::Driver(const envoy::config::trace::v3::OpenCensusConfig& oc_config,
     256             :                const LocalInfo::LocalInfo& localinfo, Api::Api& api)
     257           0 :     : oc_config_(oc_config), local_info_(localinfo) {
     258             :   // To give user a chance to correct initially invalid configuration and try to apply it once again
     259             :   // without a need to restart Envoy, validation checks must be done prior to any side effects.
     260           0 :   if (oc_config.stackdriver_exporter_enabled() && oc_config.has_stackdriver_grpc_service() &&
     261           0 :       !oc_config.stackdriver_grpc_service().has_google_grpc()) {
     262           0 :     throw EnvoyException("Opencensus stackdriver tracer only support GoogleGrpc.");
     263           0 :   }
     264           0 :   if (oc_config.ocagent_exporter_enabled() && oc_config.has_ocagent_grpc_service() &&
     265           0 :       !oc_config.ocagent_grpc_service().has_google_grpc()) {
     266           0 :     throw EnvoyException("Opencensus ocagent tracer only supports GoogleGrpc.");
     267           0 :   }
     268             :   // Process-wide side effects.
     269           0 :   if (oc_config.has_trace_config()) {
     270           0 :     applyTraceConfig(oc_config.trace_config());
     271           0 :   }
     272           0 :   if (oc_config.stdout_exporter_enabled()) {
     273           0 :     ::opencensus::exporters::trace::StdoutExporter::Register();
     274           0 :   }
     275           0 :   if (oc_config.stackdriver_exporter_enabled()) {
     276           0 :     ::opencensus::exporters::trace::StackdriverOptions opts;
     277           0 :     opts.project_id = oc_config.stackdriver_project_id();
     278           0 :     if (!oc_config.stackdriver_address().empty()) {
     279           0 :       auto channel =
     280           0 :           grpc::CreateChannel(oc_config.stackdriver_address(), grpc::InsecureChannelCredentials());
     281           0 :       opts.trace_service_stub = ::google::devtools::cloudtrace::v2::TraceService::NewStub(channel);
     282           0 :     } else if (oc_config.has_stackdriver_grpc_service() &&
     283           0 :                oc_config.stackdriver_grpc_service().has_google_grpc()) {
     284           0 : #ifdef ENVOY_GOOGLE_GRPC
     285           0 :       envoy::config::core::v3::GrpcService stackdriver_service =
     286           0 :           oc_config.stackdriver_grpc_service();
     287           0 :       if (stackdriver_service.google_grpc().target_uri().empty()) {
     288             :         // If stackdriver server address is not provided, the default production stackdriver
     289             :         // address will be used.
     290           0 :         stackdriver_service.mutable_google_grpc()->set_target_uri(GoogleStackdriverTraceAddress);
     291           0 :       }
     292           0 :       auto channel = Envoy::Grpc::GoogleGrpcUtils::createChannel(stackdriver_service, api);
     293             :       // TODO(bianpengyuan): add tests for trace_service_stub and initial_metadata options with mock
     294             :       // stubs.
     295           0 :       opts.trace_service_stub = ::google::devtools::cloudtrace::v2::TraceService::NewStub(channel);
     296           0 :       const auto& initial_metadata = stackdriver_service.initial_metadata();
     297           0 :       if (!initial_metadata.empty()) {
     298           0 :         opts.prepare_client_context = [initial_metadata](grpc::ClientContext* ctx) {
     299           0 :           for (const auto& metadata : initial_metadata) {
     300           0 :             ctx->AddMetadata(metadata.key(), metadata.value());
     301           0 :           }
     302           0 :         };
     303           0 :       }
     304             : #else
     305             :       throw EnvoyException("Opencensus tracer: cannot handle stackdriver google grpc service, "
     306             :                            "google grpc is not built in.");
     307             : #endif
     308           0 :     }
     309           0 :     ::opencensus::exporters::trace::StackdriverExporter::Register(std::move(opts));
     310           0 :   }
     311           0 :   if (oc_config.zipkin_exporter_enabled()) {
     312           0 :     ::opencensus::exporters::trace::ZipkinExporterOptions opts(oc_config.zipkin_url());
     313           0 :     opts.service_name = local_info_.clusterName();
     314           0 :     ::opencensus::exporters::trace::ZipkinExporter::Register(opts);
     315           0 :   }
     316           0 :   if (oc_config.ocagent_exporter_enabled()) {
     317           0 :     ::opencensus::exporters::trace::OcAgentOptions opts;
     318           0 :     if (!oc_config.ocagent_address().empty()) {
     319           0 :       opts.address = oc_config.ocagent_address();
     320           0 :     } else if (oc_config.has_ocagent_grpc_service() &&
     321           0 :                oc_config.ocagent_grpc_service().has_google_grpc()) {
     322           0 : #ifdef ENVOY_GOOGLE_GRPC
     323           0 :       const envoy::config::core::v3::GrpcService& ocagent_service =
     324           0 :           oc_config.ocagent_grpc_service();
     325           0 :       auto channel = Envoy::Grpc::GoogleGrpcUtils::createChannel(ocagent_service, api);
     326           0 :       opts.trace_service_stub =
     327           0 :           ::opencensus::proto::agent::trace::v1::TraceService::NewStub(channel);
     328             : #else
     329             :       throw EnvoyException("Opencensus tracer: cannot handle ocagent google grpc service, google "
     330             :                            "grpc is not built in.");
     331             : #endif
     332           0 :     }
     333           0 :     opts.service_name = local_info_.clusterName();
     334           0 :     ::opencensus::exporters::trace::OcAgentExporter::Register(std::move(opts));
     335           0 :   }
     336           0 : }
     337             : 
     338           0 : void Driver::applyTraceConfig(const opencensus::proto::trace::v1::TraceConfig& config) {
     339           0 :   using SamplerCase = opencensus::proto::trace::v1::TraceConfig::SamplerCase;
     340           0 :   using opencensus::proto::trace::v1::ConstantSampler;
     341           0 :   constexpr double kDefaultSamplingProbability = 1e-4;
     342           0 :   double probability = kDefaultSamplingProbability;
     343             : 
     344           0 :   switch (config.sampler_case()) {
     345           0 :   case SamplerCase::kProbabilitySampler:
     346           0 :     probability = config.probability_sampler().samplingprobability();
     347           0 :     break;
     348           0 :   case SamplerCase::kConstantSampler:
     349           0 :     switch (config.constant_sampler().decision()) {
     350           0 :     case ConstantSampler::ALWAYS_OFF:
     351           0 :       probability = 0.;
     352           0 :       break;
     353           0 :     case ConstantSampler::ALWAYS_ON:
     354           0 :     case ConstantSampler::ALWAYS_PARENT:
     355           0 :       probability = 1.;
     356           0 :       break;
     357           0 :     default:
     358           0 :       break; /* Keep default probability. */
     359           0 :     }
     360           0 :     break;
     361           0 :   case SamplerCase::kRateLimitingSampler:
     362           0 :     ENVOY_LOG(error, "RateLimitingSampler is not supported.");
     363           0 :     break;
     364           0 :   case SamplerCase::SAMPLER_NOT_SET:
     365           0 :     break; // Keep default.
     366           0 :   default:
     367           0 :     ENVOY_LOG(error, "Unknown sampler type in TraceConfig.");
     368           0 :   }
     369             : 
     370           0 :   ::opencensus::trace::TraceConfig::SetCurrentTraceParams(::opencensus::trace::TraceParams{
     371           0 :       uint32_t(config.max_number_of_attributes()), uint32_t(config.max_number_of_annotations()),
     372           0 :       uint32_t(config.max_number_of_message_events()), uint32_t(config.max_number_of_links()),
     373           0 :       ::opencensus::trace::ProbabilitySampler(probability)});
     374           0 : }
     375             : 
     376             : Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config,
     377             :                                    Tracing::TraceContext& trace_context,
     378             :                                    const StreamInfo::StreamInfo& stream_info,
     379             :                                    const std::string& operation_name,
     380           0 :                                    Tracing::Decision tracing_decision) {
     381           0 :   return std::make_unique<Span>(config, oc_config_, trace_context, operation_name,
     382           0 :                                 stream_info.startTime(), tracing_decision);
     383           0 : }
     384             : 
     385             : } // namespace OpenCensus
     386             : } // namespace Tracers
     387             : } // namespace Extensions
     388             : } // namespace Envoy

Generated by: LCOV version 1.15