Line data Source code
1 : #include "source/extensions/tracers/opentelemetry/opentelemetry_tracer_impl.h" 2 : 3 : #include <string> 4 : 5 : #include "envoy/common/optref.h" 6 : #include "envoy/config/trace/v3/opentelemetry.pb.h" 7 : 8 : #include "source/common/common/empty_string.h" 9 : #include "source/common/common/logger.h" 10 : #include "source/common/config/utility.h" 11 : #include "source/common/tracing/http_tracer_impl.h" 12 : #include "source/extensions/tracers/opentelemetry/grpc_trace_exporter.h" 13 : #include "source/extensions/tracers/opentelemetry/http_trace_exporter.h" 14 : #include "source/extensions/tracers/opentelemetry/resource_detectors/resource_detector.h" 15 : #include "source/extensions/tracers/opentelemetry/resource_detectors/resource_provider.h" 16 : #include "source/extensions/tracers/opentelemetry/samplers/sampler.h" 17 : #include "source/extensions/tracers/opentelemetry/span_context.h" 18 : #include "source/extensions/tracers/opentelemetry/span_context_extractor.h" 19 : #include "source/extensions/tracers/opentelemetry/trace_exporter.h" 20 : #include "source/extensions/tracers/opentelemetry/tracer.h" 21 : 22 : #include "opentelemetry/proto/collector/trace/v1/trace_service.pb.h" 23 : #include "opentelemetry/proto/trace/v1/trace.pb.h" 24 : 25 : namespace Envoy { 26 : namespace Extensions { 27 : namespace Tracers { 28 : namespace OpenTelemetry { 29 : 30 : namespace { 31 : 32 : SamplerSharedPtr 33 : tryCreateSamper(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetry_config, 34 0 : Server::Configuration::TracerFactoryContext& context) { 35 0 : SamplerSharedPtr sampler; 36 0 : if (opentelemetry_config.has_sampler()) { 37 0 : auto& sampler_config = opentelemetry_config.sampler(); 38 0 : auto* factory = Envoy::Config::Utility::getFactory<SamplerFactory>(sampler_config); 39 0 : if (!factory) { 40 0 : throw EnvoyException(fmt::format("Sampler factory not found: '{}'", sampler_config.name())); 41 0 : } 42 0 : sampler = factory->createSampler(sampler_config.typed_config(), context); 43 0 : } 44 0 : return sampler; 45 0 : } 46 : 47 0 : OTelSpanKind getSpanKind(const Tracing::Config& config) { 48 : // If this is downstream span that be created by 'startSpan' for downstream request, then 49 : // set the span type based on the spawnUpstreamSpan flag and traffic direction: 50 : // * If separate tracing span will be created for upstream request, then set span type to 51 : // SERVER because the downstream span should be server span in trace chain. 52 : // * If separate tracing span will not be created for upstream request, that means the 53 : // Envoy will not be treated as independent hop in trace chain and then set span type 54 : // based on the traffic direction. 55 0 : return (config.spawnUpstreamSpan() ? ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER 56 0 : : config.operationName() == Tracing::OperationName::Egress 57 0 : ? ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_CLIENT 58 0 : : ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER); 59 0 : } 60 : 61 : } // namespace 62 : 63 : Driver::Driver(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetry_config, 64 : Server::Configuration::TracerFactoryContext& context) 65 0 : : Driver(opentelemetry_config, context, ResourceProviderImpl{}) {} 66 : 67 : Driver::Driver(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetry_config, 68 : Server::Configuration::TracerFactoryContext& context, 69 : const ResourceProvider& resource_provider) 70 : : tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()), 71 : tracing_stats_{OPENTELEMETRY_TRACER_STATS( 72 0 : POOL_COUNTER_PREFIX(context.serverFactoryContext().scope(), "tracing.opentelemetry"))} { 73 0 : auto& factory_context = context.serverFactoryContext(); 74 : 75 0 : Resource resource = resource_provider.getResource(opentelemetry_config, context); 76 0 : ResourceConstSharedPtr resource_ptr = std::make_shared<Resource>(std::move(resource)); 77 : 78 0 : if (opentelemetry_config.has_grpc_service() && opentelemetry_config.has_http_service()) { 79 0 : throw EnvoyException( 80 0 : "OpenTelemetry Tracer cannot have both gRPC and HTTP exporters configured. " 81 0 : "OpenTelemetry tracer will be disabled."); 82 0 : } 83 : 84 : // Create the sampler if configured 85 0 : SamplerSharedPtr sampler = tryCreateSamper(opentelemetry_config, context); 86 : 87 : // Create the tracer in Thread Local Storage. 88 0 : tls_slot_ptr_->set([opentelemetry_config, &factory_context, this, resource_ptr, 89 0 : sampler](Event::Dispatcher& dispatcher) { 90 0 : OpenTelemetryTraceExporterPtr exporter; 91 0 : if (opentelemetry_config.has_grpc_service()) { 92 0 : Grpc::AsyncClientFactoryPtr&& factory = 93 0 : factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService( 94 0 : opentelemetry_config.grpc_service(), factory_context.scope(), true); 95 0 : const Grpc::RawAsyncClientSharedPtr& async_client_shared_ptr = 96 0 : factory->createUncachedRawAsyncClient(); 97 0 : exporter = std::make_unique<OpenTelemetryGrpcTraceExporter>(async_client_shared_ptr); 98 0 : } else if (opentelemetry_config.has_http_service()) { 99 0 : exporter = std::make_unique<OpenTelemetryHttpTraceExporter>( 100 0 : factory_context.clusterManager(), opentelemetry_config.http_service()); 101 0 : } 102 0 : TracerPtr tracer = std::make_unique<Tracer>( 103 0 : std::move(exporter), factory_context.timeSource(), factory_context.api().randomGenerator(), 104 0 : factory_context.runtime(), dispatcher, tracing_stats_, resource_ptr, sampler); 105 0 : return std::make_shared<TlsTracer>(std::move(tracer)); 106 0 : }); 107 0 : } 108 : 109 : Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config, 110 : Tracing::TraceContext& trace_context, 111 : const StreamInfo::StreamInfo& stream_info, 112 : const std::string& operation_name, 113 0 : Tracing::Decision tracing_decision) { 114 : // Get tracer from TLS and start span. 115 0 : auto& tracer = tls_slot_ptr_->getTyped<Driver::TlsTracer>().tracer(); 116 0 : SpanContextExtractor extractor(trace_context); 117 0 : const auto span_kind = getSpanKind(config); 118 0 : if (!extractor.propagationHeaderPresent()) { 119 : // No propagation header, so we can create a fresh span with the given decision. 120 0 : Tracing::SpanPtr new_open_telemetry_span = tracer.startSpan( 121 0 : operation_name, stream_info.startTime(), tracing_decision, trace_context, span_kind); 122 0 : return new_open_telemetry_span; 123 0 : } else { 124 : // Try to extract the span context. If we can't, just return a null span. 125 0 : absl::StatusOr<SpanContext> span_context = extractor.extractSpanContext(); 126 0 : if (span_context.ok()) { 127 0 : return tracer.startSpan(operation_name, stream_info.startTime(), span_context.value(), 128 0 : trace_context, span_kind); 129 0 : } else { 130 0 : ENVOY_LOG(trace, "Unable to extract span context: ", span_context.status()); 131 0 : return std::make_unique<Tracing::NullSpan>(); 132 0 : } 133 0 : } 134 0 : } 135 : 136 0 : Driver::TlsTracer::TlsTracer(TracerPtr tracer) : tracer_(std::move(tracer)) {} 137 : 138 0 : Tracer& Driver::TlsTracer::tracer() { 139 0 : ASSERT(tracer_); 140 0 : return *tracer_; 141 0 : } 142 : 143 : } // namespace OpenTelemetry 144 : } // namespace Tracers 145 : } // namespace Extensions 146 : } // namespace Envoy