diff --git a/api/include/opentelemetry/trace/context.h b/api/include/opentelemetry/trace/context.h index b68fe9e95a..cd8395d768 100644 --- a/api/include/opentelemetry/trace/context.h +++ b/api/include/opentelemetry/trace/context.h @@ -23,6 +23,16 @@ inline nostd::shared_ptr GetSpan(const context::Context &context) noexcept return nostd::shared_ptr(new DefaultSpan(SpanContext::GetInvalid())); } +inline bool IsRootSpan(const context::Context &context) noexcept +{ + context::ContextValue is_root_span = context.GetValue(kIsRootSpanKey); + if (nostd::holds_alternative(is_root_span)) + { + return nostd::get(is_root_span); + } + return false; +} + // Set Span into explicit context inline context::Context SetSpan(context::Context &context, nostd::shared_ptr span) noexcept { diff --git a/api/include/opentelemetry/trace/span_metadata.h b/api/include/opentelemetry/trace/span_metadata.h index 5e615ea537..d2d6a9f85d 100644 --- a/api/include/opentelemetry/trace/span_metadata.h +++ b/api/include/opentelemetry/trace/span_metadata.h @@ -20,7 +20,8 @@ enum class SpanKind }; // The key identifies the active span in the current context. -constexpr char kSpanKey[] = "active_span"; +constexpr char kSpanKey[] = "active_span"; +constexpr char kIsRootSpanKey[] = "is_root_span"; // StatusCode - Represents the canonical set of status codes of a finished Span. enum class StatusCode diff --git a/api/include/opentelemetry/trace/span_startoptions.h b/api/include/opentelemetry/trace/span_startoptions.h index 2180394d72..8a2165b0f0 100644 --- a/api/include/opentelemetry/trace/span_startoptions.h +++ b/api/include/opentelemetry/trace/span_startoptions.h @@ -34,8 +34,31 @@ struct StartSpanOptions // Explicitly set the parent of a Span. // - // This defaults to an invalid span context. In this case, the Span is - // automatically parented to the currently active span. + // The `parent` field is designed to establish parent-child relationships + // in tracing spans. It can be set to either a `SpanContext` or a + // `context::Context` object. + // + // - When set to valid `SpanContext`, it directly assigns a specific Span as the parent + // of the newly created Span. + // + // - Alternatively, setting the `parent` field to a `context::Context` allows for + // more nuanced parent identification: + // 1. If the `Context` contains a Span object, this Span is treated as the parent. + // 2. If the `Context` contains the boolean flag `is_root_span` set to `true`, + // it indicates that the new Span should be treated as a root Span, i.e., it + // does not have a parent Span. + // Example Usage: + // ```cpp + // trace_api::StartSpanOptions options; + // opentelemetry::context::Context root; + // root = root.SetValue(kIsRootSpanKey, true); + // options.parent = root; + // auto root_span = tracer->StartSpan("span root", options); + // ``` + // + // - If the `parent` field is not set, the newly created Span will inherit the + // parent of the currently active Span (if any) in the current context. + // nostd::variant parent = SpanContext::GetInvalid(); // TODO: diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 6ca7b37df5..c722d60326 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -43,6 +43,13 @@ nostd::shared_ptr Tracer::StartSpan( { parent_context = span_context; } + else + { + if (opentelemetry::trace::IsRootSpan(context)) + { + parent_context = opentelemetry::trace::SpanContext{false, false}; + } + } } opentelemetry::trace::TraceId trace_id; diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index 36cc135a1d..61ad24be1d 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -1008,6 +1008,26 @@ TEST(Tracer, WithActiveSpan) spans = span_data->GetSpans(); ASSERT_EQ(1, spans.size()); EXPECT_EQ("span 2", spans.at(0)->GetName()); + EXPECT_EQ(spans.at(0).get()->GetParentSpanId(), span_first->GetContext().span_id()); + EXPECT_EQ(spans.at(0).get()->GetTraceId(), span_first->GetContext().trace_id()); + + { + trace_api::StartSpanOptions options; + opentelemetry::context::Context c1; + c1 = c1.SetValue(opentelemetry::trace::kIsRootSpanKey, true); + options.parent = c1; + auto root_span = tracer->StartSpan("span root", options); + + spans = span_data->GetSpans(); + ASSERT_EQ(0, spans.size()); + + root_span->End(); + } + spans = span_data->GetSpans(); + ASSERT_EQ(1, spans.size()); + EXPECT_EQ("span root", spans.at(0)->GetName()); + EXPECT_EQ(spans.at(0).get()->GetParentSpanId(), opentelemetry::trace::SpanId()); + EXPECT_NE(spans.at(0).get()->GetTraceId(), span_first->GetContext().trace_id()); span_first->End(); }