Skip to content

Commit 21dbbaf

Browse files
Tracing: Allow extract span context data from request headers and inject new span context into it (#388)
1 parent faa44ef commit 21dbbaf

8 files changed

Lines changed: 96 additions & 29 deletions

File tree

include/envoy/http/header_map.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ class HeaderEntry {
205205
HEADER_FUNC(Host) \
206206
HEADER_FUNC(KeepAlive) \
207207
HEADER_FUNC(Method) \
208+
HEADER_FUNC(OtSpanContext) \
208209
HEADER_FUNC(Path) \
209210
HEADER_FUNC(ProxyConnection) \
210211
HEADER_FUNC(RequestId) \

include/envoy/tracing/http_tracer.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ class Driver {
3636
public:
3737
virtual ~Driver() {}
3838

39-
virtual SpanPtr startSpan(const std::string& operation_name, SystemTime start_time) PURE;
39+
/**
40+
* Start driver specific span.
41+
*/
42+
virtual SpanPtr startSpan(Http::HeaderMap& request_headers, const std::string& operation_name,
43+
SystemTime start_time) PURE;
4044
};
4145

4246
typedef std::unique_ptr<Driver> DriverPtr;
@@ -49,7 +53,7 @@ class HttpTracer {
4953
public:
5054
virtual ~HttpTracer() {}
5155

52-
virtual SpanPtr startSpan(const Config& config, const Http::HeaderMap& request_headers,
56+
virtual SpanPtr startSpan(const Config& config, Http::HeaderMap& request_headers,
5357
const Http::AccessLog::RequestInfo& request_info) PURE;
5458
};
5559

source/common/http/headers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class Headers {
4242
const LowerCaseString KeepAlive{"keep-alive"};
4343
const LowerCaseString Location{"location"};
4444
const LowerCaseString Method{":method"};
45+
const LowerCaseString OtSpanContext{"x-ot-span-context"};
4546
const LowerCaseString Path{":path"};
4647
const LowerCaseString ProxyConnection{"proxy-connection"};
4748
const LowerCaseString RequestId{"x-request-id"};

source/common/tracing/http_tracer_impl.cc

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,10 @@ void HttpTracerUtility::finalizeSpan(Span& active_span,
135135
HttpTracerImpl::HttpTracerImpl(DriverPtr&& driver, const LocalInfo::LocalInfo& local_info)
136136
: driver_(std::move(driver)), local_info_(local_info) {}
137137

138-
SpanPtr HttpTracerImpl::startSpan(const Config& config, const Http::HeaderMap& request_headers,
138+
SpanPtr HttpTracerImpl::startSpan(const Config& config, Http::HeaderMap& request_headers,
139139
const Http::AccessLog::RequestInfo& request_info) {
140-
SpanPtr active_span = driver_->startSpan(config.operationName(), request_info.startTime());
140+
SpanPtr active_span =
141+
driver_->startSpan(request_headers, config.operationName(), request_info.startTime());
141142
if (active_span) {
142143
HttpTracerUtility::populateSpan(*active_span, local_info_.nodeName(), request_headers,
143144
request_info);
@@ -244,11 +245,35 @@ LightStepDriver::LightStepDriver(const Json::Object& config,
244245
});
245246
}
246247

247-
SpanPtr LightStepDriver::startSpan(const std::string& operation_name, SystemTime start_time) {
248-
lightstep::Span span = tls_.getTyped<TlsLightStepTracer>(tls_slot_).tracer_.StartSpan(
249-
operation_name, {lightstep::StartTimestamp(start_time)});
248+
SpanPtr LightStepDriver::startSpan(Http::HeaderMap& request_headers,
249+
const std::string& operation_name, SystemTime start_time) {
250+
lightstep::Tracer& tracer = tls_.getTyped<TlsLightStepTracer>(tls_slot_).tracer_;
251+
LightStepSpanPtr active_span;
252+
253+
if (request_headers.OtSpanContext()) {
254+
// Extract downstream context from HTTP carrier.
255+
lightstep::envoy::CarrierStruct ctx;
256+
ctx.ParseFromString(request_headers.OtSpanContext()->value().c_str());
257+
258+
lightstep::SpanContext parent_span_ctx = tracer.Extract(
259+
lightstep::CarrierFormat::EnvoyProtoCarrier, lightstep::envoy::ProtoReader(ctx));
260+
lightstep::Span ls_span =
261+
tracer.StartSpan(operation_name, {lightstep::ChildOf(parent_span_ctx),
262+
lightstep::StartTimestamp(start_time)});
263+
active_span.reset(new LightStepSpan(ls_span));
264+
} else {
265+
lightstep::Span ls_span =
266+
tracer.StartSpan(operation_name, {lightstep::StartTimestamp(start_time)});
267+
active_span.reset(new LightStepSpan(ls_span));
268+
}
269+
270+
// Inject newly created span context into HTTP carrier.
271+
lightstep::envoy::CarrierStruct ctx;
272+
tracer.Inject(active_span->context(), lightstep::CarrierFormat::EnvoyProtoCarrier,
273+
lightstep::envoy::ProtoWriter(&ctx));
274+
request_headers.insertOtSpanContext().value(ctx.SerializeAsString());
250275

251-
return SpanPtr{new LightStepSpan(span)};
276+
return std::move(active_span);
252277
}
253278

254279
void LightStepRecorder::onFailure(Http::AsyncClient::FailureReason) {

source/common/tracing/http_tracer_impl.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "common/http/header_map_impl.h"
1010
#include "common/json/json_loader.h"
1111

12+
#include "lightstep/envoy.h"
1213
#include "lightstep/tracer.h"
1314

1415
namespace Tracing {
@@ -67,8 +68,7 @@ class HttpTracerUtility {
6768
class HttpNullTracer : public HttpTracer {
6869
public:
6970
// Tracing::HttpTracer
70-
SpanPtr startSpan(const Config&, const Http::HeaderMap&,
71-
const Http::AccessLog::RequestInfo&) override {
71+
SpanPtr startSpan(const Config&, Http::HeaderMap&, const Http::AccessLog::RequestInfo&) override {
7272
return nullptr;
7373
}
7474
};
@@ -78,7 +78,7 @@ class HttpTracerImpl : public HttpTracer {
7878
HttpTracerImpl(DriverPtr&& driver, const LocalInfo::LocalInfo& local_info);
7979

8080
// Tracing::HttpTracer
81-
SpanPtr startSpan(const Config& config, const Http::HeaderMap& request_headers,
81+
SpanPtr startSpan(const Config& config, Http::HeaderMap& request_headers,
8282
const Http::AccessLog::RequestInfo& request_info) override;
8383

8484
private:
@@ -94,10 +94,14 @@ class LightStepSpan : public Span {
9494
void finishSpan() override;
9595
void setTag(const std::string& name, const std::string& value) override;
9696

97+
lightstep::SpanContext context() { return span_.context(); }
98+
9799
private:
98100
lightstep::Span span_;
99101
};
100102

103+
typedef std::unique_ptr<LightStepSpan> LightStepSpanPtr;
104+
101105
/**
102106
* LightStep (http://lightstep.com/) provides tracing capabilities, aggregation, visualization of
103107
* application trace data.
@@ -111,7 +115,8 @@ class LightStepDriver : public Driver {
111115
std::unique_ptr<lightstep::TracerOptions> options);
112116

113117
// Tracer::TracingDriver
114-
SpanPtr startSpan(const std::string& operation_name, SystemTime start_time) override;
118+
SpanPtr startSpan(Http::HeaderMap& request_headers, const std::string& operation_name,
119+
SystemTime start_time) override;
115120

116121
Upstream::ClusterManager& clusterManager() { return cm_; }
117122
Upstream::ClusterInfoPtr cluster() { return cluster_; }

test/common/http/conn_manager_impl_test.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,10 @@ TEST_F(HttpConnectionManagerImplTest, StartSpanOnlyHealthCheckRequest) {
243243
setup(false, "");
244244

245245
NiceMock<Tracing::MockSpan>* span = new NiceMock<Tracing::MockSpan>();
246+
246247
EXPECT_CALL(tracer_, startSpan_(_, _, _)).WillOnce(Return(span));
247248
EXPECT_CALL(*span, finishSpan()).Times(0);
249+
248250
EXPECT_CALL(runtime_.snapshot_, featureEnabled("tracing.global_enabled", 100, _))
249251
.WillOnce(Return(true));
250252

test/common/tracing/http_tracer_impl_test.cc

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -352,9 +352,10 @@ class LightStepDriverTest : public Test {
352352
}
353353

354354
const std::string operation_name_{"test"};
355-
const Http::TestHeaderMapImpl request_headers_{
355+
Http::TestHeaderMapImpl request_headers_{
356356
{":path", "/"}, {":method", "GET"}, {"x-request-id", "foo"}};
357357
const Http::TestHeaderMapImpl response_headers_{{":status", "500"}};
358+
SystemTime start_time_;
358359

359360
std::unique_ptr<LightStepDriver> driver_;
360361
NiceMock<Event::MockTimer>* timer_;
@@ -447,7 +448,7 @@ TEST(HttpTracerImplTest, BasicFunctionalityNullSpan) {
447448

448449
HttpTracerImpl tracer(std::move(driver_ptr), local_info);
449450

450-
EXPECT_CALL(*driver, startSpan_(operation_name, time)).WillOnce(Return(nullptr));
451+
EXPECT_CALL(*driver, startSpan_(_, operation_name, time)).WillOnce(Return(nullptr));
451452

452453
tracer.startSpan(config, request_headers, request_info);
453454
}
@@ -471,7 +472,7 @@ TEST(HttpTracerImplTest, BasicFunctionalityNodeSet) {
471472
HttpTracerImpl tracer(std::move(driver_ptr), local_info);
472473

473474
NiceMock<MockSpan>* span = new NiceMock<MockSpan>();
474-
EXPECT_CALL(*driver, startSpan_(operation_name, time)).WillOnce(Return(span));
475+
EXPECT_CALL(*driver, startSpan_(_, operation_name, time)).WillOnce(Return(span));
475476

476477
EXPECT_CALL(*span, setTag(_, _)).Times(testing::AnyNumber());
477478
EXPECT_CALL(*span, setTag("node_id", "node_name"));
@@ -499,16 +500,17 @@ TEST_F(LightStepDriverTest, FlushSeveralSpans) {
499500
return &request;
500501
}));
501502

502-
SystemTime start_time;
503503
EXPECT_CALL(runtime_.snapshot_, getInteger("tracing.lightstep.min_flush_spans", 5))
504504
.Times(2)
505505
.WillRepeatedly(Return(2));
506506
EXPECT_CALL(runtime_.snapshot_, getInteger("tracing.lightstep.request_timeout", 5000U))
507507
.WillOnce(Return(5000U));
508508

509-
SpanPtr first_span = driver_->startSpan(operation_name_, start_time);
509+
Http::TestHeaderMapImpl headers;
510+
SpanPtr first_span = driver_->startSpan(headers, operation_name_, start_time_);
510511
first_span->finishSpan();
511-
SpanPtr second_span = driver_->startSpan(operation_name_, start_time);
512+
513+
SpanPtr second_span = driver_->startSpan(headers, operation_name_, start_time_);
512514
second_span->finishSpan();
513515

514516
Http::MessagePtr msg(new Http::ResponseMessageImpl(
@@ -539,11 +541,10 @@ TEST_F(LightStepDriverTest, FlushSpansTimer) {
539541
const Optional<std::chrono::milliseconds> timeout(std::chrono::seconds(5));
540542
EXPECT_CALL(cm_.async_client_, send_(_, _, timeout));
541543

542-
SystemTime start_time;
543544
EXPECT_CALL(runtime_.snapshot_, getInteger("tracing.lightstep.min_flush_spans", 5))
544545
.WillOnce(Return(5));
545546

546-
SpanPtr span = driver_->startSpan(operation_name_, start_time);
547+
SpanPtr span = driver_->startSpan(request_headers_, operation_name_, start_time_);
547548
span->finishSpan();
548549

549550
// Timer should be re-enabled.
@@ -579,15 +580,13 @@ TEST_F(LightStepDriverTest, FlushOneSpanGrpcFailure) {
579580

580581
return &request;
581582
}));
582-
583-
SystemTime start_time;
584-
585583
EXPECT_CALL(runtime_.snapshot_, getInteger("tracing.lightstep.min_flush_spans", 5))
586584
.WillOnce(Return(1));
587585
EXPECT_CALL(runtime_.snapshot_, getInteger("tracing.lightstep.request_timeout", 5000U))
588586
.WillOnce(Return(5000U));
589587

590-
SpanPtr span = driver_->startSpan(operation_name_, start_time);
588+
Http::TestHeaderMapImpl headers;
589+
SpanPtr span = driver_->startSpan(headers, operation_name_, start_time_);
591590
span->finishSpan();
592591

593592
Http::MessagePtr msg(new Http::ResponseMessageImpl(
@@ -605,4 +604,32 @@ TEST_F(LightStepDriverTest, FlushOneSpanGrpcFailure) {
605604
EXPECT_EQ(1U, stats_.counter("tracing.lightstep.spans_sent").value());
606605
}
607606

607+
TEST_F(LightStepDriverTest, SerializeAndDeserializeContext) {
608+
setupValidDriver();
609+
610+
// Supply bogus context, that will be simply ignored.
611+
const std::string invalid_context = "not valid context";
612+
request_headers_.insertOtSpanContext().value(invalid_context);
613+
driver_->startSpan(request_headers_, operation_name_, start_time_);
614+
615+
std::string injected_ctx = request_headers_.OtSpanContext()->value().c_str();
616+
EXPECT_FALSE(injected_ctx.empty());
617+
618+
// Supply empty context.
619+
request_headers_.removeOtSpanContext();
620+
SpanPtr span = driver_->startSpan(request_headers_, operation_name_, start_time_);
621+
622+
injected_ctx = request_headers_.OtSpanContext()->value().c_str();
623+
EXPECT_FALSE(injected_ctx.empty());
624+
625+
// Context can be parsed fine.
626+
lightstep::envoy::CarrierStruct ctx;
627+
ctx.ParseFromString(injected_ctx);
628+
629+
// Supply parent context, request_headers has properly populated x-ot-span-context.
630+
SpanPtr span_with_parent = driver_->startSpan(request_headers_, operation_name_, start_time_);
631+
injected_ctx = request_headers_.OtSpanContext()->value().c_str();
632+
EXPECT_FALSE(injected_ctx.empty());
633+
}
634+
608635
} // Tracing

test/mocks/tracing/mocks.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ class MockHttpTracer : public HttpTracer {
2626
MockHttpTracer();
2727
~MockHttpTracer();
2828

29-
SpanPtr startSpan(const Config& config, const Http::HeaderMap& request_headers,
29+
SpanPtr startSpan(const Config& config, Http::HeaderMap& request_headers,
3030
const Http::AccessLog::RequestInfo& request_info) override {
3131
return SpanPtr{startSpan_(config, request_headers, request_info)};
3232
}
3333

34-
MOCK_METHOD3(startSpan_, Span*(const Config& config, const Http::HeaderMap& request_headers,
34+
MOCK_METHOD3(startSpan_, Span*(const Config& config, Http::HeaderMap& request_headers,
3535
const Http::AccessLog::RequestInfo& request_info));
3636
};
3737

@@ -40,11 +40,13 @@ class MockDriver : public Driver {
4040
MockDriver();
4141
~MockDriver();
4242

43-
SpanPtr startSpan(const std::string& operation_name, SystemTime start_time) override {
44-
return SpanPtr{startSpan_(operation_name, start_time)};
43+
SpanPtr startSpan(Http::HeaderMap& request_headers, const std::string& operation_name,
44+
SystemTime start_time) override {
45+
return SpanPtr{startSpan_(request_headers, operation_name, start_time)};
4546
}
4647

47-
MOCK_METHOD2(startSpan_, Span*(const std::string& operation_name, SystemTime start_time));
48+
MOCK_METHOD3(startSpan_, Span*(Http::HeaderMap& request_headers,
49+
const std::string& operation_name, SystemTime start_time));
4850
};
4951

5052
} // Tracing

0 commit comments

Comments
 (0)