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

          Line data    Source code
       1             : #include "source/extensions/tracers/opentelemetry/span_context_extractor.h"
       2             : 
       3             : #include "envoy/tracing/tracer.h"
       4             : 
       5             : #include "source/common/http/header_map_impl.h"
       6             : #include "source/common/tracing/trace_context_impl.h"
       7             : 
       8             : #include "absl/strings/escaping.h"
       9             : #include "span_context.h"
      10             : 
      11             : namespace Envoy {
      12             : namespace Extensions {
      13             : namespace Tracers {
      14             : namespace OpenTelemetry {
      15             : namespace {
      16             : 
      17             : // See https://www.w3.org/TR/trace-context/#traceparent-header
      18             : constexpr int kTraceparentHeaderSize = 55; // 2 + 1 + 32 + 1 + 16 + 1 + 2
      19             : constexpr int kVersionHexSize = 2;
      20             : constexpr int kTraceIdHexSize = 32;
      21             : constexpr int kParentIdHexSize = 16;
      22             : constexpr int kTraceFlagsHexSize = 2;
      23             : 
      24           0 : bool isValidHex(const absl::string_view& input) {
      25           0 :   return std::all_of(input.begin(), input.end(),
      26           0 :                      [](const char& c) { return absl::ascii_isxdigit(c); });
      27           0 : }
      28             : 
      29           0 : bool isAllZeros(const absl::string_view& input) {
      30           0 :   return std::all_of(input.begin(), input.end(), [](const char& c) { return c == '0'; });
      31           0 : }
      32             : 
      33             : } // namespace
      34             : 
      35             : SpanContextExtractor::SpanContextExtractor(Tracing::TraceContext& trace_context)
      36           0 :     : trace_context_(trace_context) {}
      37             : 
      38           0 : SpanContextExtractor::~SpanContextExtractor() = default;
      39             : 
      40           0 : bool SpanContextExtractor::propagationHeaderPresent() {
      41           0 :   auto propagation_header = OpenTelemetryConstants::get().TRACE_PARENT.get(trace_context_);
      42           0 :   return propagation_header.has_value();
      43           0 : }
      44             : 
      45           0 : absl::StatusOr<SpanContext> SpanContextExtractor::extractSpanContext() {
      46           0 :   auto propagation_header = OpenTelemetryConstants::get().TRACE_PARENT.get(trace_context_);
      47           0 :   if (!propagation_header.has_value()) {
      48             :     // We should have already caught this, but just in case.
      49           0 :     return absl::InvalidArgumentError("No propagation header found");
      50           0 :   }
      51           0 :   auto header_value_string = propagation_header.value();
      52             : 
      53           0 :   if (header_value_string.size() != kTraceparentHeaderSize) {
      54           0 :     return absl::InvalidArgumentError("Invalid traceparent header length");
      55           0 :   }
      56             :   // Try to split it into its component parts:
      57           0 :   std::vector<absl::string_view> propagation_header_components =
      58           0 :       absl::StrSplit(header_value_string, '-', absl::SkipEmpty());
      59           0 :   if (propagation_header_components.size() != 4) {
      60           0 :     return absl::InvalidArgumentError("Invalid traceparent hyphenation");
      61           0 :   }
      62           0 :   absl::string_view version = propagation_header_components[0];
      63           0 :   absl::string_view trace_id = propagation_header_components[1];
      64           0 :   absl::string_view parent_id = propagation_header_components[2];
      65           0 :   absl::string_view trace_flags = propagation_header_components[3];
      66           0 :   if (version.size() != kVersionHexSize || trace_id.size() != kTraceIdHexSize ||
      67           0 :       parent_id.size() != kParentIdHexSize || trace_flags.size() != kTraceFlagsHexSize) {
      68           0 :     return absl::InvalidArgumentError("Invalid traceparent field sizes");
      69           0 :   }
      70           0 :   if (!isValidHex(version) || !isValidHex(trace_id) || !isValidHex(parent_id) ||
      71           0 :       !isValidHex(trace_flags)) {
      72           0 :     return absl::InvalidArgumentError("Invalid header hex");
      73           0 :   }
      74             :   // As per the traceparent header definition, if the trace-id or parent-id are all zeros, they are
      75             :   // invalid and must be ignored.
      76           0 :   if (isAllZeros(trace_id)) {
      77           0 :     return absl::InvalidArgumentError("Invalid trace id");
      78           0 :   }
      79           0 :   if (isAllZeros(parent_id)) {
      80           0 :     return absl::InvalidArgumentError("Invalid parent id");
      81           0 :   }
      82             : 
      83             :   // Set whether or not the span is sampled from the trace flags.
      84             :   // See https://w3c.github.io/trace-context/#trace-flags.
      85           0 :   char decoded_trace_flags = absl::HexStringToBytes(trace_flags).front();
      86           0 :   bool sampled = (decoded_trace_flags & 1);
      87             : 
      88             :   // If a tracestate header is received without an accompanying traceparent header,
      89             :   // it is invalid and MUST be discarded. Because we're already checking for the
      90             :   // traceparent header above, we don't need to check here.
      91             :   // See https://www.w3.org/TR/trace-context/#processing-model-for-working-with-trace-context
      92           0 :   absl::string_view tracestate_key = OpenTelemetryConstants::get().TRACE_STATE.key();
      93           0 :   std::vector<std::string> tracestate_values;
      94             :   // Multiple tracestate header fields MUST be handled as specified by RFC7230 Section 3.2.2 Field
      95             :   // Order.
      96           0 :   trace_context_.forEach(
      97           0 :       [&tracestate_key, &tracestate_values](absl::string_view key, absl::string_view value) {
      98           0 :         if (key == tracestate_key) {
      99           0 :           tracestate_values.push_back(std::string{value});
     100           0 :         }
     101           0 :         return true;
     102           0 :       });
     103           0 :   std::string tracestate = absl::StrJoin(tracestate_values, ",");
     104             : 
     105           0 :   SpanContext span_context(version, trace_id, parent_id, sampled, tracestate);
     106           0 :   return span_context;
     107           0 : }
     108             : 
     109             : } // namespace OpenTelemetry
     110             : } // namespace Tracers
     111             : } // namespace Extensions
     112             : } // namespace Envoy

Generated by: LCOV version 1.15