Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/extensions/tracers/datadog/tracer.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/extensions/tracers/datadog/tracer.h"
2
3
#include <memory>
4
#include <utility>
5
6
#include "envoy/tracing/trace_context.h"
7
8
#include "source/common/common/assert.h"
9
#include "source/common/config/utility.h"
10
#include "source/common/tracing/null_span_impl.h"
11
#include "source/extensions/tracers/datadog/agent_http_client.h"
12
#include "source/extensions/tracers/datadog/dict_util.h"
13
#include "source/extensions/tracers/datadog/event_scheduler.h"
14
#include "source/extensions/tracers/datadog/logger.h"
15
#include "source/extensions/tracers/datadog/span.h"
16
#include "source/extensions/tracers/datadog/time_util.h"
17
18
#include "datadog/dict_reader.h"
19
#include "datadog/error.h"
20
#include "datadog/sampling_priority.h"
21
#include "datadog/span_config.h"
22
#include "datadog/trace_segment.h"
23
#include "datadog/tracer_config.h"
24
25
namespace Envoy {
26
namespace Extensions {
27
namespace Tracers {
28
namespace Datadog {
29
namespace {
30
31
std::shared_ptr<Tracer::ThreadLocalTracer> makeThreadLocalTracer(
32
    datadog::tracing::TracerConfig config, Upstream::ClusterManager& cluster_manager,
33
    const std::string& collector_cluster, const std::string& collector_reference_host,
34
    TracerStats& tracer_stats, Event::Dispatcher& dispatcher, spdlog::logger& logger,
35
0
    TimeSource& time_source) {
36
0
  config.logger = std::make_shared<Logger>(logger);
37
0
  config.agent.event_scheduler = std::make_shared<EventScheduler>(dispatcher);
38
0
  config.agent.http_client = std::make_shared<AgentHTTPClient>(
39
0
      cluster_manager, collector_cluster, collector_reference_host, tracer_stats, time_source);
40
41
0
  datadog::tracing::Expected<datadog::tracing::FinalizedTracerConfig> maybe_config =
42
0
      datadog::tracing::finalize_config(config);
43
0
  if (datadog::tracing::Error* error = maybe_config.if_error()) {
44
0
    datadog::tracing::StringView prefix =
45
0
        "Unable to configure Datadog tracer. Tracing is now disabled. Error: ";
46
0
    config.logger->log_error(error->with_prefix(prefix));
47
0
    return std::make_shared<Tracer::ThreadLocalTracer>();
48
0
  }
49
50
0
  return std::make_shared<Tracer::ThreadLocalTracer>(*maybe_config);
51
0
}
52
53
} // namespace
54
55
Tracer::ThreadLocalTracer::ThreadLocalTracer(const datadog::tracing::FinalizedTracerConfig& config)
56
0
    : tracer(config) {}
57
58
Tracer::Tracer(const std::string& collector_cluster, const std::string& collector_reference_host,
59
               const datadog::tracing::TracerConfig& config,
60
               Upstream::ClusterManager& cluster_manager, Stats::Scope& scope,
61
               ThreadLocal::SlotAllocator& thread_local_slot_allocator, TimeSource& time_source)
62
    : tracer_stats_(makeTracerStats(scope)),
63
      thread_local_slot_(
64
0
          ThreadLocal::TypedSlot<ThreadLocalTracer>::makeUnique(thread_local_slot_allocator)) {
65
0
  const bool allow_added_via_api = true;
66
0
  THROW_IF_NOT_OK_REF(Config::Utility::checkCluster("envoy.tracers.datadog", collector_cluster,
67
0
                                                    cluster_manager, allow_added_via_api)
68
0
                          .status());
69
70
0
  thread_local_slot_->set([&logger = ENVOY_LOGGER(), collector_cluster, collector_reference_host,
71
0
                           config, &tracer_stats = tracer_stats_, &cluster_manager,
72
0
                           &time_source](Event::Dispatcher& dispatcher) {
73
0
    return makeThreadLocalTracer(config, cluster_manager, collector_cluster,
74
0
                                 collector_reference_host, tracer_stats, dispatcher, logger,
75
0
                                 time_source);
76
0
  });
77
0
}
78
79
// Tracer::TracingDriver
80
81
Tracing::SpanPtr Tracer::startSpan(const Tracing::Config&, Tracing::TraceContext& trace_context,
82
                                   const StreamInfo::StreamInfo& stream_info,
83
                                   const std::string& operation_name,
84
0
                                   Tracing::Decision tracing_decision) {
85
0
  ThreadLocalTracer& thread_local_tracer = **thread_local_slot_;
86
0
  if (!thread_local_tracer.tracer) {
87
0
    return std::make_unique<Tracing::NullSpan>();
88
0
  }
89
90
  // The OpenTracing implementation ignored the `Tracing::Config` argument,
91
  // so we will as well.
92
0
  datadog::tracing::SpanConfig span_config;
93
  // The `operation_name` parameter to this function more closely matches
94
  // Datadog's concept of "resource name." Datadog's "span name," or "operation
95
  // name," instead describes the category of operation being performed, which
96
  // here we hard-code.
97
0
  span_config.name = "envoy.proxy";
98
0
  span_config.resource = operation_name;
99
0
  span_config.start = estimateTime(stream_info.startTime());
100
101
0
  TraceContextReader reader{trace_context};
102
0
  datadog::tracing::Span span =
103
0
      extractOrCreateSpan(*thread_local_tracer.tracer, span_config, reader);
104
105
  // If we did not extract a sampling decision, and if Envoy is telling us to
106
  // drop the trace, then we treat that as a "user drop" (manual override).
107
  //
108
  // If Envoy is telling us to keep the trace, then we leave it up to the
109
  // tracer's internal sampler (which might decide to drop the trace anyway).
110
0
  if (!span.trace_segment().sampling_decision().has_value() && !tracing_decision.traced) {
111
0
    span.trace_segment().override_sampling_priority(
112
0
        int(datadog::tracing::SamplingPriority::USER_DROP));
113
0
  }
114
115
0
  return std::make_unique<Span>(std::move(span));
116
0
}
117
118
datadog::tracing::Span Tracer::extractOrCreateSpan(datadog::tracing::Tracer& tracer,
119
                                                   const datadog::tracing::SpanConfig& span_config,
120
0
                                                   const datadog::tracing::DictReader& reader) {
121
0
  datadog::tracing::Expected<datadog::tracing::Span> maybe_span =
122
0
      tracer.extract_span(reader, span_config);
123
0
  if (datadog::tracing::Error* error = maybe_span.if_error()) {
124
    // We didn't extract a span. Either there's no span to extract, or an
125
    // error occurred during extraction.
126
    //
127
    // Either way, we're going to create a new root span, but if an error
128
    // occurred we're going to log the error.
129
0
    if (error->code != datadog::tracing::Error::NO_SPAN_TO_EXTRACT) {
130
0
      ENVOY_LOG(
131
0
          error,
132
0
          "Unable to extract span context. Creating a new trace instead. Error [error {}]: {}",
133
0
          int(error->code), error->message);
134
0
    }
135
136
0
    return tracer.create_span(span_config);
137
0
  }
138
139
0
  return std::move(*maybe_span);
140
0
}
141
142
} // namespace Datadog
143
} // namespace Tracers
144
} // namespace Extensions
145
} // namespace Envoy