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

          Line data    Source code
       1             : #include "source/extensions/tracers/xray/xray_tracer_impl.h"
       2             : 
       3             : #include "source/common/common/macros.h"
       4             : #include "source/common/common/utility.h"
       5             : #include "source/common/http/headers.h"
       6             : #include "source/extensions/tracers/xray/localized_sampling.h"
       7             : #include "source/extensions/tracers/xray/tracer.h"
       8             : #include "source/extensions/tracers/xray/xray_configuration.h"
       9             : 
      10             : namespace Envoy {
      11             : namespace Extensions {
      12             : namespace Tracers {
      13             : namespace XRay {
      14             : 
      15             : namespace {
      16             : constexpr auto DefaultDaemonEndpoint = "127.0.0.1:2000";
      17           0 : XRayHeader parseXRayHeader(const Http::LowerCaseString& header) {
      18           0 :   const auto& lowered_header = header.get();
      19           0 :   XRayHeader result;
      20           0 :   for (const auto& token : StringUtil::splitToken(lowered_header, ";")) {
      21           0 :     if (absl::StartsWith(token, "root=")) {
      22           0 :       result.trace_id_ = std::string(StringUtil::cropLeft(token, "="));
      23           0 :     } else if (absl::StartsWith(token, "parent=")) {
      24           0 :       result.parent_id_ = std::string(StringUtil::cropLeft(token, "="));
      25           0 :     } else if (absl::StartsWith(token, "sampled=")) {
      26           0 :       const auto s = StringUtil::cropLeft(token, "=");
      27           0 :       if (s == "1") {
      28           0 :         result.sample_decision_ = SamplingDecision::Sampled;
      29           0 :       } else if (s == "0") {
      30           0 :         result.sample_decision_ = SamplingDecision::NotSampled;
      31           0 :       } else {
      32           0 :         result.sample_decision_ = SamplingDecision::Unknown;
      33           0 :       }
      34           0 :     }
      35           0 :   }
      36           0 :   return result;
      37           0 : }
      38             : } // namespace
      39             : 
      40             : Driver::Driver(const XRayConfiguration& config,
      41             :                Server::Configuration::TracerFactoryContext& context)
      42             :     : xray_config_(config),
      43           0 :       tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()) {
      44             : 
      45           0 :   const std::string daemon_endpoint =
      46           0 :       config.daemon_endpoint_.empty() ? DefaultDaemonEndpoint : config.daemon_endpoint_;
      47             : 
      48           0 :   ENVOY_LOG(debug, "send X-Ray generated segments to daemon address on {}", daemon_endpoint);
      49           0 :   sampling_strategy_ = std::make_unique<XRay::LocalizedSamplingStrategy>(
      50           0 :       xray_config_.sampling_rules_, context.serverFactoryContext().api().randomGenerator(),
      51           0 :       context.serverFactoryContext().timeSource());
      52             : 
      53           0 :   tls_slot_ptr_->set([this, daemon_endpoint,
      54           0 :                       &context](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr {
      55           0 :     DaemonBrokerPtr broker = std::make_unique<DaemonBrokerImpl>(daemon_endpoint);
      56           0 :     TracerPtr tracer = std::make_unique<Tracer>(
      57           0 :         xray_config_.segment_name_, xray_config_.origin_, xray_config_.aws_metadata_,
      58           0 :         std::move(broker), context.serverFactoryContext().timeSource(),
      59           0 :         context.serverFactoryContext().api().randomGenerator());
      60           0 :     return std::make_shared<XRay::Driver::TlsTracer>(std::move(tracer), *this);
      61           0 :   });
      62           0 : }
      63             : 
      64             : Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config,
      65             :                                    Tracing::TraceContext& trace_context,
      66             :                                    const StreamInfo::StreamInfo& stream_info,
      67             :                                    const std::string& operation_name,
      68           0 :                                    Tracing::Decision tracing_decision) {
      69             :   // First thing is to determine whether this request will be sampled or not.
      70             :   // if there's a X-Ray header and it has a sampling decision already determined (i.e. Sample=1)
      71             :   // then we can move on; otherwise, we ask the sampling strategy whether this request should be
      72             :   // sampled or not.
      73             :   //
      74             :   // The second step is create a Span.
      75             :   // If we have a XRay TraceID in the headers, then we create a SpanContext to pass that trace-id
      76             :   // around if no TraceID (which means no x-ray header) then this is a brand new span.
      77             : 
      78             :   // TODO(suniltheta) - how do we factor this into the logic above
      79           0 :   UNREFERENCED_PARAMETER(tracing_decision);
      80           0 :   const auto header = xRayTraceHeader().get(trace_context);
      81           0 :   absl::optional<bool> should_trace;
      82           0 :   XRayHeader xray_header;
      83           0 :   if (header.has_value()) {
      84             :     // This is an implicitly untrusted header, so only the first value is used.
      85           0 :     Http::LowerCaseString lowered_header_value{header.value()};
      86           0 :     xray_header = parseXRayHeader(lowered_header_value);
      87             :     // if the sample_decision in the x-ray header is unknown then we try to make a decision based
      88             :     // on the sampling strategy
      89           0 :     if (xray_header.sample_decision_ == SamplingDecision::Sampled) {
      90           0 :       should_trace = true;
      91           0 :     } else if (xray_header.sample_decision_ == SamplingDecision::NotSampled) {
      92           0 :       should_trace = false;
      93           0 :     } else {
      94           0 :       ENVOY_LOG(
      95           0 :           trace,
      96           0 :           "Unable to determine from the X-Ray trace header whether request is sampled or not");
      97           0 :     }
      98           0 :   }
      99             : 
     100           0 :   if (!should_trace.has_value()) {
     101           0 :     const SamplingRequest request{trace_context.host(), trace_context.method(),
     102           0 :                                   trace_context.path()};
     103             : 
     104           0 :     should_trace = sampling_strategy_->shouldTrace(request);
     105           0 :   }
     106             : 
     107           0 :   auto* tracer = tls_slot_ptr_->getTyped<Driver::TlsTracer>().tracer_.get();
     108           0 :   if (should_trace.value()) {
     109           0 :     return tracer->startSpan(config, operation_name, stream_info.startTime(),
     110           0 :                              header.has_value() ? absl::optional<XRayHeader>(xray_header)
     111           0 :                                                 : absl::nullopt,
     112           0 :                              xForwardedForHeader().get(trace_context));
     113           0 :   }
     114             : 
     115             :   // Instead of returning nullptr, we return a Span that is marked as not-sampled.
     116             :   // This is important to communicate that information to upstream services (see injectContext()).
     117             :   // Otherwise, the upstream service can decide to sample the request regardless and we end up with
     118             :   // more samples than we asked for.
     119           0 :   return tracer->createNonSampledSpan(header.has_value() ? absl::optional<XRayHeader>(xray_header)
     120           0 :                                                          : absl::nullopt);
     121           0 : }
     122             : 
     123             : } // namespace XRay
     124             : } // namespace Tracers
     125             : } // namespace Extensions
     126             : } // namespace Envoy

Generated by: LCOV version 1.15