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