Line data Source code
1 : #include "source/extensions/tracers/skywalking/skywalking_tracer_impl.h" 2 : 3 : #include <memory> 4 : 5 : #include "source/common/common/macros.h" 6 : #include "source/common/common/utility.h" 7 : #include "source/common/http/path_utility.h" 8 : 9 : #include "cpp2sky/propagation.h" 10 : 11 : namespace Envoy { 12 : namespace Extensions { 13 : namespace Tracers { 14 : namespace SkyWalking { 15 : 16 : namespace { 17 : constexpr uint32_t DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE = 1024; 18 : 19 : // When the user does not provide any available configuration, in order to ensure that the service 20 : // name and instance name are not empty, use this value as the default identifier. In practice, 21 : // user should provide accurate configuration as much as possible to avoid using the default value. 22 : constexpr absl::string_view DEFAULT_SERVICE_AND_INSTANCE = "EnvoyProxy"; 23 : } // namespace 24 : 25 : using cpp2sky::createSpanContext; 26 : using cpp2sky::SpanContextPtr; 27 : 28 : Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, 29 : Server::Configuration::TracerFactoryContext& context) 30 : : tracing_stats_(std::make_shared<SkyWalkingTracerStats>( 31 : SkyWalkingTracerStats{SKYWALKING_TRACER_STATS(POOL_COUNTER_PREFIX( 32 : context.serverFactoryContext().scope(), "tracing.skywalking."))})), 33 0 : tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()) { 34 0 : loadConfig(proto_config.client_config(), context.serverFactoryContext()); 35 0 : tracing_context_factory_ = std::make_unique<TracingContextFactory>(config_); 36 0 : auto& factory_context = context.serverFactoryContext(); 37 0 : tls_slot_ptr_->set([proto_config, &factory_context, this](Event::Dispatcher& dispatcher) { 38 0 : TracerPtr tracer = std::make_unique<Tracer>(std::make_unique<TraceSegmentReporter>( 39 0 : factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService( 40 0 : proto_config.grpc_service(), factory_context.scope(), true), 41 0 : dispatcher, factory_context.api().randomGenerator(), tracing_stats_, 42 0 : config_.delayed_buffer_size(), config_.token())); 43 0 : return std::make_shared<TlsTracer>(std::move(tracer)); 44 0 : }); 45 0 : } 46 : 47 : Tracing::SpanPtr Driver::startSpan(const Tracing::Config&, Tracing::TraceContext& trace_context, 48 : const StreamInfo::StreamInfo&, const std::string&, 49 0 : Tracing::Decision decision) { 50 0 : auto& tracer = tls_slot_ptr_->getTyped<Driver::TlsTracer>().tracer(); 51 0 : TracingContextPtr tracing_context; 52 : // TODO(shikugawa): support extension span header. 53 0 : auto propagation_header = skywalkingPropagationHeaderKey().get(trace_context); 54 0 : if (!propagation_header.has_value()) { 55 : // Although a sampling flag can be added to the propagation header, it will be ignored by most 56 : // of SkyWalking agent. The agent will enable tracing anyway if it see the propagation header. 57 : // So, if no propagation header is provided and sampling decision of Envoy is false, we need not 58 : // propagate this sampling decision to the upstream. A null span will be used directly. 59 0 : if (!decision.traced) { 60 0 : return std::make_unique<Tracing::NullSpan>(); 61 0 : } 62 0 : tracing_context = tracing_context_factory_->create(); 63 0 : } else { 64 0 : auto header_value_string = propagation_header.value(); 65 : 66 : // TODO(wbpcode): catching all exceptions is not a good practice. But the cpp2sky library may 67 : // throw exception that not be wrapped by TracerException. See 68 : // https://github.com/SkyAPM/cpp2sky/issues/117. So, we need to catch all exceptions here to 69 : // avoid Envoy crash in the runtime. 70 0 : TRY_NEEDS_AUDIT { 71 0 : SpanContextPtr span_context = 72 0 : createSpanContext(toStdStringView(header_value_string)); // NOLINT(std::string_view) 73 0 : tracing_context = tracing_context_factory_->create(span_context); 74 0 : } 75 0 : END_TRY catch (std::exception& e) { 76 0 : ENVOY_LOG( 77 0 : warn, 78 0 : "New SkyWalking Span/Segment with previous span context cannot be created for error: {}", 79 0 : e.what()); 80 0 : if (!decision.traced) { 81 0 : return std::make_unique<Tracing::NullSpan>(); 82 0 : } 83 0 : tracing_context = tracing_context_factory_->create(); 84 0 : } 85 0 : } 86 : 87 0 : return tracer.startSpan(trace_context.path(), trace_context.protocol(), tracing_context); 88 0 : } 89 : 90 : void Driver::loadConfig(const envoy::config::trace::v3::ClientConfig& client_config, 91 0 : Server::Configuration::ServerFactoryContext& server_factory_context) { 92 0 : config_.set_service_name(!client_config.service_name().empty() 93 0 : ? client_config.service_name() 94 0 : : (!server_factory_context.localInfo().clusterName().empty() 95 0 : ? server_factory_context.localInfo().clusterName() 96 0 : : DEFAULT_SERVICE_AND_INSTANCE.data())); 97 0 : config_.set_instance_name(!client_config.instance_name().empty() 98 0 : ? client_config.instance_name() 99 0 : : (!server_factory_context.localInfo().nodeName().empty() 100 0 : ? server_factory_context.localInfo().nodeName() 101 0 : : DEFAULT_SERVICE_AND_INSTANCE.data())); 102 0 : config_.set_token(client_config.backend_token()); 103 0 : config_.set_delayed_buffer_size(PROTOBUF_GET_WRAPPED_OR_DEFAULT( 104 0 : client_config, max_cache_size, DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE)); 105 0 : } 106 : 107 0 : Driver::TlsTracer::TlsTracer(TracerPtr tracer) : tracer_(std::move(tracer)) {} 108 : 109 0 : Tracer& Driver::TlsTracer::tracer() { 110 0 : ASSERT(tracer_); 111 0 : return *tracer_; 112 0 : } 113 : 114 : } // namespace SkyWalking 115 : } // namespace Tracers 116 : } // namespace Extensions 117 : } // namespace Envoy