Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API] Create root span with active span #2427

Merged
merged 11 commits into from
Dec 5, 2023
10 changes: 10 additions & 0 deletions api/include/opentelemetry/trace/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ inline nostd::shared_ptr<Span> GetSpan(const context::Context &context) noexcept
return nostd::shared_ptr<Span>(new DefaultSpan(SpanContext::GetInvalid()));
}

inline bool IsRootSpan(const context::Context &context) noexcept
{
context::ContextValue is_root_span = context.GetValue(kIsRootSpanKey);
if (nostd::holds_alternative<bool>(is_root_span))
{
return nostd::get<bool>(is_root_span);
}
return false;
}

// Set Span into explicit context
inline context::Context SetSpan(context::Context &context, nostd::shared_ptr<Span> span) noexcept
{
Expand Down
3 changes: 2 additions & 1 deletion api/include/opentelemetry/trace/span_metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 25 additions & 2 deletions api/include/opentelemetry/trace/span_startoptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<SpanContext, context::Context> parent = SpanContext::GetInvalid();

// TODO:
Expand Down
7 changes: 7 additions & 0 deletions sdk/src/trace/tracer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ nostd::shared_ptr<opentelemetry::trace::Span> Tracer::StartSpan(
{
parent_context = span_context;
}
else
{
if (opentelemetry::trace::IsRootSpan(context))
{
parent_context = opentelemetry::trace::SpanContext{false, false};
}
}
}

opentelemetry::trace::TraceId trace_id;
Expand Down
20 changes: 20 additions & 0 deletions sdk/test/trace/tracer_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down