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::SpanContextSharedPtr;
27

            
28
Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config,
29
               Server::Configuration::TracerFactoryContext& context)
30
4
    : tracing_stats_(std::make_shared<SkyWalkingTracerStats>(
31
4
          SkyWalkingTracerStats{SKYWALKING_TRACER_STATS(POOL_COUNTER_PREFIX(
32
4
              context.serverFactoryContext().scope(), "tracing.skywalking."))})),
33
4
      tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()) {
34
4
  loadConfig(proto_config.client_config(), context.serverFactoryContext());
35
4
  tracing_context_factory_ = std::make_unique<TracingContextFactory>(config_);
36
4
  auto& factory_context = context.serverFactoryContext();
37
4
  tls_slot_ptr_->set([proto_config, &factory_context, this](Event::Dispatcher& dispatcher) {
38
4
    auto factory_or_error =
39
4
        factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService(
40
4
            proto_config.grpc_service(), factory_context.scope(), true);
41
4
    THROW_IF_NOT_OK_REF(factory_or_error.status());
42
4
    TracerPtr tracer = std::make_unique<Tracer>(std::make_unique<TraceSegmentReporter>(
43
4
        std::move(factory_or_error.value()), dispatcher, factory_context.api().randomGenerator(),
44
4
        tracing_stats_, config_.delayed_buffer_size(), config_.token()));
45
4
    return std::make_shared<TlsTracer>(std::move(tracer));
46
4
  });
47
4
}
48

            
49
Tracing::SpanPtr Driver::startSpan(const Tracing::Config&, Tracing::TraceContext& trace_context,
50
                                   const StreamInfo::StreamInfo&, const std::string&,
51
8
                                   Tracing::Decision decision) {
52
8
  auto& tracer = tls_slot_ptr_->getTyped<Driver::TlsTracer>().tracer();
53
8
  TracingContextSharedPtr tracing_context;
54
  // TODO(shikugawa): support extension span header.
55
8
  auto propagation_header = skywalkingPropagationHeaderKey().get(trace_context);
56
8
  if (!propagation_header.has_value()) {
57
    // Although a sampling flag can be added to the propagation header, it will be ignored by most
58
    // of SkyWalking agent. The agent will enable tracing anyway if it see the propagation header.
59
    // So, if no propagation header is provided and sampling decision of Envoy is false, we need not
60
    // propagate this sampling decision to the upstream. A null span will be used directly.
61
3
    if (!decision.traced) {
62
1
      return std::make_unique<Tracing::NullSpan>();
63
1
    }
64
2
    tracing_context = tracing_context_factory_->create();
65
5
  } else {
66
5
    auto header_value_string = propagation_header.value();
67

            
68
    // TODO(wbpcode): catching all exceptions is not a good practice. But the cpp2sky library may
69
    // throw exception that not be wrapped by TracerException. See
70
    // https://github.com/SkyAPM/cpp2sky/issues/117. So, we need to catch all exceptions here to
71
    // avoid Envoy crash in the runtime.
72
5
    TRY_NEEDS_AUDIT {
73
5
      SpanContextSharedPtr span_context =
74
5
          createSpanContext(toStdStringView(header_value_string)); // NOLINT(std::string_view)
75
5
      tracing_context = tracing_context_factory_->create(span_context);
76
5
    }
77
5
    END_TRY catch (std::exception& e) {
78
4
      ENVOY_LOG(
79
4
          warn,
80
4
          "New SkyWalking Span/Segment with previous span context cannot be created for error: {}",
81
4
          e.what());
82
4
      if (!decision.traced) {
83
2
        return std::make_unique<Tracing::NullSpan>();
84
2
      }
85
2
      tracing_context = tracing_context_factory_->create();
86
2
    }
87
5
  }
88

            
89
5
  return tracer.startSpan(trace_context.path(), trace_context.protocol(), tracing_context);
90
8
}
91

            
92
void Driver::loadConfig(const envoy::config::trace::v3::ClientConfig& client_config,
93
4
                        Server::Configuration::ServerFactoryContext& server_factory_context) {
94
4
  config_.set_service_name(!client_config.service_name().empty()
95
4
                               ? client_config.service_name()
96
4
                               : (!server_factory_context.localInfo().clusterName().empty()
97
2
                                      ? server_factory_context.localInfo().clusterName()
98
2
                                      : DEFAULT_SERVICE_AND_INSTANCE.data()));
99
4
  config_.set_instance_name(!client_config.instance_name().empty()
100
4
                                ? client_config.instance_name()
101
4
                                : (!server_factory_context.localInfo().nodeName().empty()
102
2
                                       ? server_factory_context.localInfo().nodeName()
103
2
                                       : DEFAULT_SERVICE_AND_INSTANCE.data()));
104
4
  config_.set_token(client_config.backend_token());
105
4
  config_.set_delayed_buffer_size(PROTOBUF_GET_WRAPPED_OR_DEFAULT(
106
4
      client_config, max_cache_size, DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE));
107
4
}
108

            
109
4
Driver::TlsTracer::TlsTracer(TracerPtr tracer) : tracer_(std::move(tracer)) {}
110

            
111
8
Tracer& Driver::TlsTracer::tracer() {
112
8
  ASSERT(tracer_);
113
8
  return *tracer_;
114
8
}
115

            
116
} // namespace SkyWalking
117
} // namespace Tracers
118
} // namespace Extensions
119
} // namespace Envoy