Line data Source code
1 : #include "source/extensions/tracers/common/ot/opentracing_driver_impl.h"
2 :
3 : #include <sstream>
4 :
5 : #include "envoy/stats/scope.h"
6 :
7 : #include "source/common/common/assert.h"
8 : #include "source/common/common/base64.h"
9 : #include "source/common/common/utility.h"
10 : #include "source/common/http/header_map_impl.h"
11 : #include "source/common/tracing/common_values.h"
12 : #include "source/common/tracing/null_span_impl.h"
13 : #include "source/common/tracing/trace_context_impl.h"
14 :
15 : namespace Envoy {
16 : namespace Extensions {
17 : namespace Tracers {
18 : namespace Common {
19 : namespace Ot {
20 :
21 : Http::RegisterCustomInlineHeader<Http::CustomInlineHeaderRegistry::Type::RequestHeaders>
22 : ot_span_context_handle(Http::CustomHeaders::get().OtSpanContext);
23 :
24 : namespace {
25 :
26 0 : const Tracing::TraceContextHandler& otSpanContextHeader() {
27 0 : CONSTRUCT_ON_FIRST_USE(Tracing::TraceContextHandler, Http::CustomHeaders::get().OtSpanContext);
28 0 : }
29 :
30 : /**
31 : * TODO(wbpcode): Use opentracing::TextMapWriter to replace opentracing::HTTPHeadersWriter.
32 : */
33 : class OpenTracingHeadersWriter : public opentracing::HTTPHeadersWriter {
34 : public:
35 : explicit OpenTracingHeadersWriter(Tracing::TraceContext& trace_context)
36 0 : : trace_context_(trace_context) {}
37 :
38 : // opentracing::HTTPHeadersWriter
39 : opentracing::expected<void> Set(opentracing::string_view key,
40 0 : opentracing::string_view value) const override {
41 0 : Http::LowerCaseString lowercase_key{{key.data(), key.size()}};
42 0 : trace_context_.set(lowercase_key, {value.data(), value.size()});
43 0 : return {};
44 0 : }
45 :
46 : private:
47 : Tracing::TraceContext& trace_context_;
48 : };
49 :
50 : /**
51 : * TODO(wbpcode): Use opentracing::TextMapReader to replace opentracing::HTTPHeadersReader.
52 : */
53 : class OpenTracingHeadersReader : public opentracing::HTTPHeadersReader {
54 : public:
55 : explicit OpenTracingHeadersReader(const Tracing::TraceContext& trace_context)
56 0 : : trace_context_(trace_context) {}
57 :
58 : using OpenTracingCb = std::function<opentracing::expected<void>(opentracing::string_view,
59 : opentracing::string_view)>;
60 :
61 : // opentracing::HTTPHeadersReader
62 : opentracing::expected<opentracing::string_view>
63 0 : LookupKey(opentracing::string_view key) const override {
64 0 : Http::LowerCaseString lowercase_key{{key.data(), key.size()}};
65 0 : const auto entry = trace_context_.get(lowercase_key);
66 0 : if (entry.has_value()) {
67 0 : return opentracing::string_view{entry.value().data(), entry.value().length()};
68 0 : } else {
69 0 : return opentracing::make_unexpected(opentracing::key_not_found_error);
70 0 : }
71 0 : }
72 :
73 0 : opentracing::expected<void> ForeachKey(OpenTracingCb f) const override {
74 0 : trace_context_.forEach([cb = std::move(f)](absl::string_view key, absl::string_view val) {
75 0 : opentracing::string_view opentracing_key{key.data(), key.length()};
76 0 : opentracing::string_view opentracing_val{val.data(), val.length()};
77 0 : return static_cast<bool>(cb(opentracing_key, opentracing_val));
78 0 : });
79 0 : return {};
80 0 : }
81 :
82 : private:
83 : const Tracing::TraceContext& trace_context_;
84 : };
85 : } // namespace
86 :
87 : OpenTracingSpan::OpenTracingSpan(OpenTracingDriver& driver,
88 : std::unique_ptr<opentracing::Span>&& span)
89 0 : : driver_{driver}, span_(std::move(span)) {}
90 :
91 0 : void OpenTracingSpan::finishSpan() { span_->FinishWithOptions(finish_options_); }
92 :
93 0 : void OpenTracingSpan::setOperation(absl::string_view operation) {
94 0 : span_->SetOperationName({operation.data(), operation.length()});
95 0 : }
96 :
97 0 : void OpenTracingSpan::setTag(absl::string_view name, absl::string_view value) {
98 0 : span_->SetTag({name.data(), name.length()},
99 0 : opentracing::v2::string_view{value.data(), value.length()});
100 0 : }
101 :
102 0 : void OpenTracingSpan::log(SystemTime timestamp, const std::string& event) {
103 0 : opentracing::LogRecord record{timestamp, {{Tracing::Logs::get().EventKey, event}}};
104 0 : finish_options_.log_records.emplace_back(std::move(record));
105 0 : }
106 :
107 0 : void OpenTracingSpan::setBaggage(absl::string_view key, absl::string_view value) {
108 0 : span_->SetBaggageItem({key.data(), key.length()}, {value.data(), value.length()});
109 0 : }
110 :
111 0 : std::string OpenTracingSpan::getBaggage(absl::string_view key) {
112 0 : return span_->BaggageItem({key.data(), key.length()});
113 0 : }
114 :
115 : void OpenTracingSpan::injectContext(Tracing::TraceContext& trace_context,
116 0 : const Upstream::HostDescriptionConstSharedPtr&) {
117 0 : if (driver_.propagationMode() == OpenTracingDriver::PropagationMode::SingleHeader) {
118 : // Inject the span context using Envoy's single-header format.
119 0 : std::ostringstream oss;
120 0 : const opentracing::expected<void> was_successful =
121 0 : span_->tracer().Inject(span_->context(), oss);
122 0 : if (!was_successful) {
123 0 : ENVOY_LOG(debug, "Failed to inject span context: {}", was_successful.error().message());
124 0 : driver_.tracerStats().span_context_injection_error_.inc();
125 0 : return;
126 0 : }
127 0 : const std::string current_span_context = oss.str();
128 0 : otSpanContextHeader().setRefKey(
129 0 : trace_context, Base64::encode(current_span_context.c_str(), current_span_context.length()));
130 0 : } else {
131 : // Inject the context using the tracer's standard header format.
132 0 : const OpenTracingHeadersWriter writer{trace_context};
133 0 : const opentracing::expected<void> was_successful =
134 0 : span_->tracer().Inject(span_->context(), writer);
135 0 : if (!was_successful) {
136 0 : ENVOY_LOG(debug, "Failed to inject span context: {}", was_successful.error().message());
137 0 : driver_.tracerStats().span_context_injection_error_.inc();
138 0 : return;
139 0 : }
140 0 : }
141 0 : }
142 :
143 0 : void OpenTracingSpan::setSampled(bool sampled) {
144 0 : span_->SetTag(opentracing::ext::sampling_priority, sampled ? 1 : 0);
145 0 : }
146 :
147 : Tracing::SpanPtr OpenTracingSpan::spawnChild(const Tracing::Config&, const std::string& name,
148 0 : SystemTime start_time) {
149 0 : std::unique_ptr<opentracing::Span> ot_span = span_->tracer().StartSpan(
150 0 : name, {opentracing::ChildOf(&span_->context()), opentracing::StartTimestamp(start_time)});
151 0 : RELEASE_ASSERT(ot_span != nullptr, "");
152 0 : return Tracing::SpanPtr{new OpenTracingSpan{driver_, std::move(ot_span)}};
153 0 : }
154 :
155 : OpenTracingDriver::OpenTracingDriver(Stats::Scope& scope)
156 0 : : tracer_stats_{OPENTRACING_TRACER_STATS(POOL_COUNTER_PREFIX(scope, "tracing.opentracing."))} {}
157 :
158 : Tracing::SpanPtr OpenTracingDriver::startSpan(const Tracing::Config& config,
159 : Tracing::TraceContext& trace_context,
160 : const StreamInfo::StreamInfo& stream_info,
161 : const std::string& operation_name,
162 0 : Tracing::Decision tracing_decision) {
163 0 : const PropagationMode propagation_mode = this->propagationMode();
164 0 : const opentracing::Tracer& tracer = this->tracer();
165 0 : std::unique_ptr<opentracing::Span> active_span;
166 0 : std::unique_ptr<opentracing::SpanContext> parent_span_ctx;
167 :
168 0 : const auto entry = otSpanContextHeader().get(trace_context);
169 0 : if (propagation_mode == PropagationMode::SingleHeader && entry.has_value()) {
170 0 : opentracing::expected<std::unique_ptr<opentracing::SpanContext>> parent_span_ctx_maybe;
171 0 : std::string parent_context = Base64::decode(std::string(entry.value()));
172 :
173 0 : if (!parent_context.empty()) {
174 0 : InputConstMemoryStream istream{parent_context.data(), parent_context.size()};
175 0 : parent_span_ctx_maybe = tracer.Extract(istream);
176 0 : } else {
177 0 : parent_span_ctx_maybe =
178 0 : opentracing::make_unexpected(opentracing::span_context_corrupted_error);
179 0 : }
180 :
181 0 : if (parent_span_ctx_maybe) {
182 0 : parent_span_ctx = std::move(*parent_span_ctx_maybe);
183 0 : } else {
184 0 : ENVOY_LOG(debug, "Failed to extract span context: {}",
185 0 : parent_span_ctx_maybe.error().message());
186 0 : tracerStats().span_context_extraction_error_.inc();
187 0 : }
188 0 : } else if (propagation_mode == PropagationMode::TracerNative) {
189 0 : const OpenTracingHeadersReader reader{trace_context};
190 0 : opentracing::expected<std::unique_ptr<opentracing::SpanContext>> parent_span_ctx_maybe =
191 0 : tracer.Extract(reader);
192 0 : if (parent_span_ctx_maybe) {
193 0 : parent_span_ctx = std::move(*parent_span_ctx_maybe);
194 0 : } else {
195 0 : ENVOY_LOG(debug, "Failed to extract span context: {}",
196 0 : parent_span_ctx_maybe.error().message());
197 0 : tracerStats().span_context_extraction_error_.inc();
198 0 : }
199 0 : }
200 0 : opentracing::StartSpanOptions options;
201 0 : options.references.emplace_back(opentracing::SpanReferenceType::ChildOfRef,
202 0 : parent_span_ctx.get());
203 0 : options.start_system_timestamp = stream_info.startTime();
204 0 : if (!tracing_decision.traced) {
205 0 : options.tags.emplace_back(opentracing::ext::sampling_priority, 0);
206 0 : }
207 0 : active_span = tracer.StartSpanWithOptions(operation_name, options);
208 0 : RELEASE_ASSERT(active_span != nullptr, "");
209 0 : active_span->SetTag(opentracing::ext::span_kind,
210 0 : config.operationName() == Tracing::OperationName::Egress
211 0 : ? opentracing::ext::span_kind_rpc_client
212 0 : : opentracing::ext::span_kind_rpc_server);
213 0 : return Tracing::SpanPtr{new OpenTracingSpan{*this, std::move(active_span)}};
214 0 : }
215 :
216 : } // namespace Ot
217 : } // namespace Common
218 : } // namespace Tracers
219 : } // namespace Extensions
220 : } // namespace Envoy
|