diff --git a/opentracing-shim/src/tracer_shim.cc b/opentracing-shim/src/tracer_shim.cc index 41c6404624..7848cba478 100644 --- a/opentracing-shim/src/tracer_shim.cc +++ b/opentracing-shim/src/tracer_shim.cc @@ -124,12 +124,21 @@ opentracing::expected TracerShim::injectImpl(const opentracing::SpanContex if (auto context_shim = SpanContextShim::extractFrom(&sc)) { auto current_context = opentelemetry::context::RuntimeContext::GetCurrent(); - // It MUST inject any non-empty Baggage even amidst no valid SpanContext. - const auto &context = - opentelemetry::baggage::SetBaggage(current_context, context_shim->baggage()); + + // Inject dummy span to provide SpanContext information + auto span_context = opentelemetry::trace::SpanContext( + context_shim->context().trace_id(), context_shim->context().span_id(), + context_shim->context().trace_flags(), false); + opentelemetry::nostd::shared_ptr sp{ + new opentelemetry::trace::DefaultSpan(span_context)}; + auto context_with_span = opentelemetry::trace::SetSpan(current_context, sp); + + // Inject any non-empty Baggage + const auto &context_with_span_baggage = + opentelemetry::baggage::SetBaggage(context_with_span, context_shim->baggage()); CarrierWriterShim carrier{writer}; - propagator->Inject(carrier, context); + propagator->Inject(carrier, context_with_span_baggage); return opentracing::make_expected(); } diff --git a/opentracing-shim/test/shim_mocks.h b/opentracing-shim/test/shim_mocks.h index 555f6cb65b..b39b2b3781 100644 --- a/opentracing-shim/test/shim_mocks.h +++ b/opentracing-shim/test/shim_mocks.h @@ -117,6 +117,18 @@ struct MockTracerProvider final : public trace_api::TracerProvider struct MockPropagator : public context::propagation::TextMapPropagator { + static constexpr const char *kTraceIdKey = "trace_id"; + static constexpr const char *kSpanIdKey = "span_id"; + static constexpr const char *kTraceFlagsKey = "trace_flags_id"; + + template + static inline std::string ToLowerBase16(const T &id) + { + char buf[N] = {0}; + id.ToLowerBase16(buf); + return std::string(buf, sizeof(buf)); + } + // Returns the context that is stored in the carrier with the TextMapCarrier as extractor. context::Context Extract(const context::propagation::TextMapCarrier &carrier, context::Context &context) noexcept override @@ -140,6 +152,24 @@ struct MockPropagator : public context::propagation::TextMapPropagator carrier.Set(k, v); return true; }); + + auto span_key_value = context.GetValue(trace_api::kSpanKey); + if (nostd::holds_alternative>(span_key_value)) + { + auto span = nostd::get>(span_key_value); + if (span) + { + // Store span context information in TextMapCarrier to allow verifying propagation + auto span_context = span->GetContext(); + carrier.Set(kTraceIdKey, ToLowerBase16( + span_context.trace_id())); + carrier.Set(kSpanIdKey, ToLowerBase16( + span_context.span_id())); + carrier.Set(kTraceFlagsKey, + ToLowerBase16(span_context.trace_flags())); + } + } + is_injected = true; } diff --git a/opentracing-shim/test/tracer_shim_test.cc b/opentracing-shim/test/tracer_shim_test.cc index 9d57bbcae4..2d3f2618da 100644 --- a/opentracing-shim/test/tracer_shim_test.cc +++ b/opentracing-shim/test/tracer_shim_test.cc @@ -218,3 +218,97 @@ TEST_F(TracerShimTest, ExtractOnlyBaggage) ASSERT_TRUE(span_context_shim->BaggageItem("foo", value)); ASSERT_EQ(value, "bar"); } + +class TracerWithSpanContext : public trace_api::Tracer +{ +public: + nostd::shared_ptr StartSpan( + nostd::string_view name, + const common::KeyValueIterable & /* attributes */, + const trace_api::SpanContextKeyValueIterable & /* links */, + const trace_api::StartSpanOptions & /* options */) noexcept override + { + constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; + trace_api::TraceId trace_id(trace_id_buf); + + constexpr uint8_t span_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8}; + trace_api::SpanId span_id(span_id_buf); + + auto span_context = trace_api::SpanContext(trace_id, span_id, GetTraceFlags(), false); + nostd::shared_ptr result(new trace_api::DefaultSpan(span_context)); + + return result; + } + + void ForceFlushWithMicroseconds(uint64_t /* timeout */) noexcept override {} + + void CloseWithMicroseconds(uint64_t /* timeout */) noexcept override {} + + static trace_api::TraceFlags GetTraceFlags() + { + return trace_api::TraceFlags(trace_api::TraceFlags::kIsSampled); + } +}; + +class TracerWithSpanContextProvider : public trace_api::TracerProvider +{ +public: + static nostd::shared_ptr Create() + { + nostd::shared_ptr result(new TracerWithSpanContextProvider()); + return result; + } + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + nostd::shared_ptr GetTracer( + nostd::string_view /* name */, + nostd::string_view /* version */, + nostd::string_view /* schema_url */, + const common::KeyValueIterable * /* attributes */) noexcept override + { + nostd::shared_ptr result(new TracerWithSpanContext()); + return result; + } +#else + nostd::shared_ptr GetTracer( + nostd::string_view /* name */, + nostd::string_view /* version */, + nostd::string_view /* schema_url */) noexcept override + { + nostd::shared_ptr result(new TracerWithSpanContext()); + return result; + } +#endif +}; + +TEST_F(TracerShimTest, InjectSpanKey) +{ + using context::propagation::TextMapPropagator; + + auto local_text_map_format = new MockPropagator(); + auto local_http_headers_format = new MockPropagator(); + + ASSERT_FALSE(local_text_map_format->is_injected); + ASSERT_FALSE(local_http_headers_format->is_injected); + + nostd::shared_ptr tracer_provider = + TracerWithSpanContextProvider::Create(); + auto local_tracer_shim = shim::TracerShim::createTracerShim( + tracer_provider, + {.text_map = nostd::shared_ptr(local_text_map_format), + .http_headers = nostd::shared_ptr(local_http_headers_format)}); + + std::unordered_map text_map; + auto span_shim = local_tracer_shim->StartSpan("a"); + local_tracer_shim->Inject(span_shim->context(), TextMapCarrier{text_map}); + + ASSERT_TRUE(local_text_map_format->is_injected); + ASSERT_FALSE(local_http_headers_format->is_injected); + + ASSERT_EQ(span_shim->context().ToTraceID(), text_map[MockPropagator::kTraceIdKey]); + ASSERT_EQ(span_shim->context().ToSpanID(), text_map[MockPropagator::kSpanIdKey]); + + char flag_buffer[2]; + TracerWithSpanContext::GetTraceFlags().ToLowerBase16(flag_buffer); + ASSERT_EQ(std::string(flag_buffer, 2), text_map[MockPropagator::kTraceFlagsKey]); +}