diff --git a/CHANGELOG.md b/CHANGELOG.md index 468fbd8f7e..ad43a3e6e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,11 @@ Increment the: * [RELEASE] Bump main branch to 1.29.0-dev [#4259](https://github.com/open-telemetry/opentelemetry-cpp/pull/4259) +* [API] Add `trace::GetSpanContext()` to read the active span's `SpanContext` + from a `Context` without the `DefaultSpan` allocation that + `GetSpan(context)->GetContext()` incurs, and use it at existing call sites. + [#4254](https://github.com/open-telemetry/opentelemetry-cpp/pull/4254) + ## [1.28.0] 2026-07-16 * [RELEASE] Bump main branch to 1.28.0-dev diff --git a/api/include/opentelemetry/trace/context.h b/api/include/opentelemetry/trace/context.h index 146f0d65f9..90ef5adc41 100644 --- a/api/include/opentelemetry/trace/context.h +++ b/api/include/opentelemetry/trace/context.h @@ -23,6 +23,33 @@ inline nostd::shared_ptr GetSpan(const context::Context &context) noexcept return nostd::shared_ptr(new DefaultSpan(SpanContext::GetInvalid())); } +// Get the SpanContext of the active span from explicit context. Falls back to a SpanContext +// stored directly in the context, and returns an invalid SpanContext if neither is present. +inline SpanContext GetSpanContext(const context::Context &context) noexcept +{ + if (!context.HasKey(kSpanKey)) + { + return SpanContext::GetInvalid(); + } + + const context::ContextValue context_value = context.GetValue(kSpanKey); + + // Get the span metadata from the active span in the context. + if (const nostd::shared_ptr *maybe_span = + nostd::get_if>(&context_value)) + { + return *maybe_span ? (*maybe_span)->GetContext() : SpanContext::GetInvalid(); + } + // Get the span metadata directly from a SpanContext in the context. + // TODO: This path is unused and may be removed in the future. + if (const nostd::shared_ptr *maybe_span_context = + nostd::get_if>(&context_value)) + { + return *maybe_span_context ? **maybe_span_context : SpanContext::GetInvalid(); + } + return SpanContext::GetInvalid(); +} + // Check if the context is from a root span inline bool IsRootSpan(const context::Context &context) noexcept { diff --git a/api/include/opentelemetry/trace/propagation/b3_propagator.h b/api/include/opentelemetry/trace/propagation/b3_propagator.h index a13d2f0767..1202cbe7de 100644 --- a/api/include/opentelemetry/trace/propagation/b3_propagator.h +++ b/api/include/opentelemetry/trace/propagation/b3_propagator.h @@ -139,7 +139,7 @@ class B3Propagator : public B3PropagatorExtractor void Inject(context::propagation::TextMapCarrier &carrier, const context::Context &context) noexcept override { - SpanContext span_context = trace::GetSpan(context)->GetContext(); + SpanContext span_context = trace::GetSpanContext(context); if (!span_context.IsValid()) { return; @@ -171,7 +171,7 @@ class B3PropagatorMultiHeader : public B3PropagatorExtractor void Inject(context::propagation::TextMapCarrier &carrier, const context::Context &context) noexcept override { - SpanContext span_context = GetSpan(context)->GetContext(); + SpanContext span_context = GetSpanContext(context); if (!span_context.IsValid()) { return; diff --git a/api/include/opentelemetry/trace/propagation/http_trace_context.h b/api/include/opentelemetry/trace/propagation/http_trace_context.h index f8f349d33e..65c6e511f1 100644 --- a/api/include/opentelemetry/trace/propagation/http_trace_context.h +++ b/api/include/opentelemetry/trace/propagation/http_trace_context.h @@ -41,7 +41,7 @@ class HttpTraceContext : public context::propagation::TextMapPropagator void Inject(context::propagation::TextMapCarrier &carrier, const context::Context &context) noexcept override { - SpanContext span_context = trace::GetSpan(context)->GetContext(); + SpanContext span_context = trace::GetSpanContext(context); if (!span_context.IsValid()) { return; diff --git a/api/include/opentelemetry/trace/propagation/jaeger.h b/api/include/opentelemetry/trace/propagation/jaeger.h index ac843f97b6..a4ff4ebc9d 100644 --- a/api/include/opentelemetry/trace/propagation/jaeger.h +++ b/api/include/opentelemetry/trace/propagation/jaeger.h @@ -23,7 +23,7 @@ class JaegerPropagator : public context::propagation::TextMapPropagator void Inject(context::propagation::TextMapCarrier &carrier, const context::Context &context) noexcept override { - SpanContext span_context = trace::GetSpan(context)->GetContext(); + SpanContext span_context = trace::GetSpanContext(context); if (!span_context.IsValid()) { return; diff --git a/api/test/trace/context_test.cc b/api/test/trace/context_test.cc index 1081fb0e7a..b72f41abf1 100644 --- a/api/test/trace/context_test.cc +++ b/api/test/trace/context_test.cc @@ -69,6 +69,48 @@ TEST(TraceContextTest, GetSpan) } } +TEST(TraceContextTest, GetSpanContext) +{ + { + context_api::Context context; + EXPECT_FALSE(trace_api::GetSpanContext(context).IsValid()); + } + + { + context_api::Context context; + auto input_span = MakeValidSpan(); + auto context_with_span = trace_api::SetSpan(context, input_span); + auto span_context = trace_api::GetSpanContext(context_with_span); + EXPECT_TRUE(span_context.IsValid()); + EXPECT_EQ(span_context, input_span->GetContext()); + } + + { + context_api::Context context; + auto context_with_null_span = + context.SetValue(trace_api::kSpanKey, nostd::shared_ptr{}); + EXPECT_FALSE(trace_api::GetSpanContext(context_with_null_span).IsValid()); + } + + { + context_api::Context context; + const auto input_span_context = MakeValidSpan()->GetContext(); + auto context_with_span_context = context.SetValue( + trace_api::kSpanKey, + nostd::shared_ptr{new trace_api::SpanContext{input_span_context}}); + auto span_context = trace_api::GetSpanContext(context_with_span_context); + EXPECT_TRUE(span_context.IsValid()); + EXPECT_EQ(span_context, input_span_context); + } + + { + context_api::Context context; + auto context_with_null_span_context = + context.SetValue(trace_api::kSpanKey, nostd::shared_ptr{}); + EXPECT_FALSE(trace_api::GetSpanContext(context_with_null_span_context).IsValid()); + } +} + TEST(TraceContextTest, SetSpan) { context_api::Context context; diff --git a/opentracing-shim/src/tracer_shim.cc b/opentracing-shim/src/tracer_shim.cc index bfc6055971..6cd5342a99 100644 --- a/opentracing-shim/src/tracer_shim.cc +++ b/opentracing-shim/src/tracer_shim.cc @@ -183,7 +183,7 @@ opentracing::expected> TracerShim::ext CarrierReaderShim carrier{reader}; auto current_context = opentelemetry::context::RuntimeContext::GetCurrent(); auto context = propagator->Extract(carrier, current_context); - auto span_context = opentelemetry::trace::GetSpan(context)->GetContext(); + auto span_context = opentelemetry::trace::GetSpanContext(context); auto baggage = opentelemetry::baggage::GetBaggage(context); // The operation MUST return a `SpanContext` Shim instance with the extracted values if any of diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h index 91e66264df..be22ba9e61 100644 --- a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h @@ -18,7 +18,6 @@ # include "opentelemetry/sdk/metrics/data/metric_data.h" # include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/trace/context.h" -# include "opentelemetry/trace/span.h" # include "opentelemetry/trace/span_context.h" # include "opentelemetry/version.h" @@ -135,14 +134,10 @@ class ReservoirCell { attributes_ = attributes; record_time_ = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now()); - auto span = opentelemetry::trace::GetSpan(context); - if (span) + const auto current_ctx = opentelemetry::trace::GetSpanContext(context); + if (current_ctx.IsValid()) { - auto current_ctx = span->GetContext(); - if (current_ctx.IsValid()) - { - context_.reset(new opentelemetry::trace::SpanContext{current_ctx}); - } + context_.reset(new opentelemetry::trace::SpanContext{current_ctx}); } } diff --git a/sdk/src/logs/logger.cc b/sdk/src/logs/logger.cc index cde8a3503c..20bc6e4562 100644 --- a/sdk/src/logs/logger.cc +++ b/sdk/src/logs/logger.cc @@ -9,13 +9,11 @@ #include "opentelemetry/common/timestamp.h" #include "opentelemetry/context/context.h" -#include "opentelemetry/context/context_value.h" #include "opentelemetry/context/runtime_context.h" #include "opentelemetry/logs/event_id.h" #include "opentelemetry/logs/log_record.h" #include "opentelemetry/logs/noop.h" #include "opentelemetry/logs/severity.h" -#include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/unique_ptr.h" #include "opentelemetry/nostd/variant.h" @@ -26,10 +24,9 @@ #include "opentelemetry/sdk/logs/logger_context.h" #include "opentelemetry/sdk/logs/processor.h" #include "opentelemetry/sdk/logs/recordable.h" -#include "opentelemetry/trace/span.h" +#include "opentelemetry/trace/context.h" #include "opentelemetry/trace/span_context.h" #include "opentelemetry/trace/span_id.h" -#include "opentelemetry/trace/span_metadata.h" #include "opentelemetry/trace/trace_flags.h" #include "opentelemetry/version.h" @@ -50,33 +47,6 @@ nostd::string_view GetEventName(const opentelemetry::logs::EventId &event_id) no : nostd::string_view{}; } -trace_api::SpanContext ExtractSpanContextFromContext(const context::Context &context) noexcept -{ - if (!context.HasKey(trace_api::kSpanKey)) - { - return trace_api::SpanContext::GetInvalid(); - } - - const context::ContextValue context_value = context.GetValue(trace_api::kSpanKey); - - // Get the span metadata from the active span in the context - if (const nostd::shared_ptr *maybe_span = - nostd::get_if>(&context_value)) - { - const nostd::shared_ptr &span = *maybe_span; - return span->GetContext(); - } - // Get the span metadata directly from a SpanContext in the context. - // TODO: This path is unused and may be removed in the future. - if (const nostd::shared_ptr *maybe_span_context = - nostd::get_if>(&context_value)) - { - const nostd::shared_ptr &span_context = *maybe_span_context; - return *span_context; - } - return trace_api::SpanContext::GetInvalid(); -} - trace_api::SpanContext ExtractSpanContext( const nostd::variant &context_or_span) noexcept { @@ -86,7 +56,7 @@ trace_api::SpanContext ExtractSpanContext( } if (const context::Context *ctx = nostd::get_if(&context_or_span)) { - return ExtractSpanContextFromContext(*ctx); + return trace_api::GetSpanContext(*ctx); } return trace_api::SpanContext::GetInvalid(); } diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index b0f0e593e8..96b2d81fc9 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -75,7 +75,7 @@ nostd::shared_ptr Tracer::StartSpan( else if (const context::Context *context = nostd::get_if(&options.parent)) { // fetch span context from parent span stored in the context - auto parent_span_context = opentelemetry::trace::GetSpan(*context)->GetContext(); + auto parent_span_context = opentelemetry::trace::GetSpanContext(*context); if (parent_span_context.IsValid()) { parent_context = parent_span_context;