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

Support determining parent span from Context while creating new Span #969

Merged
merged 8 commits into from
Sep 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 3 additions & 62 deletions api/include/opentelemetry/trace/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,80 +7,21 @@

#include "opentelemetry/common/attribute_value.h"
#include "opentelemetry/common/key_value_iterable_view.h"
#include "opentelemetry/common/timestamp.h"
#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/nostd/span.h"
#include "opentelemetry/nostd/string_view.h"
#include "opentelemetry/nostd/type_traits.h"
#include "opentelemetry/nostd/unique_ptr.h"
#include "opentelemetry/trace/canonical_code.h"
#include "opentelemetry/trace/span_context.h"
#include "opentelemetry/trace/span_metadata.h"

#include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace trace
{

// The key identifies the active span in the current context.
constexpr char kSpanKey[] = "active_span";

enum class SpanKind
{
kInternal,
kServer,
kClient,
kProducer,
kConsumer,
};

// StatusCode - Represents the canonical set of status codes of a finished Span.

enum class StatusCode
{
kUnset, // default status
kOk, // Operation has completed successfully.
kError // The operation contains an error
};

/**
* StartSpanOptions provides options to set properties of a Span at the time of
* its creation
*/
struct StartSpanOptions
{
// Optionally sets the start time of a Span.
//
// If the start time of a Span is set, timestamps from both the system clock
// and steady clock must be provided.
//
// Timestamps from the steady clock can be used to most accurately measure a
// Span's duration, while timestamps from the system clock can be used to most
// accurately place a Span's
// time point relative to other Spans collected across a distributed system.
common::SystemTimestamp start_system_time;
common::SteadyTimestamp start_steady_time;

// 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.
SpanContext parent = SpanContext::GetInvalid();

// TODO:
// SpanContext remote_parent;
// Links
SpanKind kind = SpanKind::kInternal;
};
/**
* StartEndOptions provides options to set properties of a Span when it is
* ended.
*/
struct EndSpanOptions
{
// Optionally sets the end time of a Span.
common::SteadyTimestamp end_steady_time;
};

class Tracer;

/**
Expand Down Expand Up @@ -176,7 +117,7 @@ class Span
* @param options can be used to manually define span properties like the end
* timestamp
*/
virtual void End(const EndSpanOptions &options = {}) noexcept = 0;
virtual void End(const trace::EndSpanOptions &options = {}) noexcept = 0;

virtual trace::SpanContext GetContext() const noexcept = 0;

Expand Down
43 changes: 43 additions & 0 deletions api/include/opentelemetry/trace/span_metadata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "opentelemetry/common/timestamp.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace trace
{

enum class SpanKind
{
kInternal,
kServer,
kClient,
kProducer,
kConsumer,
};

// The key identifies the active span in the current context.
constexpr char kSpanKey[] = "active_span";

// StatusCode - Represents the canonical set of status codes of a finished Span.
enum class StatusCode
{
kUnset, // default status
kOk, // Operation has completed successfully.
kError // The operation contains an error
};

/**
* EndSpanOptions provides options to set properties of a Span when it is
* ended.
*/
struct EndSpanOptions
{
// Optionally sets the end time of a Span.
common::SteadyTimestamp end_steady_time;
};

} // namespace trace
OPENTELEMETRY_END_NAMESPACE
45 changes: 45 additions & 0 deletions api/include/opentelemetry/trace/span_startoptions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "opentelemetry/context/context.h"
#include "opentelemetry/trace/span_context.h"
#include "opentelemetry/trace/span_metadata.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace trace
{

/**
* StartSpanOptions provides options to set properties of a Span at the time of
* its creation
*/
struct StartSpanOptions
{
// Optionally sets the start time of a Span.
//
// If the start time of a Span is set, timestamps from both the system clock
// and steady clock must be provided.
//
// Timestamps from the steady clock can be used to most accurately measure a
// Span's duration, while timestamps from the system clock can be used to most
// accurately place a Span's
// time point relative to other Spans collected across a distributed system.
common::SystemTimestamp start_system_time;
common::SteadyTimestamp start_steady_time;

// 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.
nostd::variant<SpanContext, opentelemetry::context::Context> parent = SpanContext::GetInvalid();

// TODO:
// SpanContext remote_parent;
// Links
SpanKind kind = SpanKind::kInternal;
};

} // namespace trace
OPENTELEMETRY_END_NAMESPACE
3 changes: 2 additions & 1 deletion api/include/opentelemetry/trace/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@

#pragma once

#include "opentelemetry/context/context.h"
#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/nostd/string_view.h"
#include "opentelemetry/nostd/unique_ptr.h"
#include "opentelemetry/trace/default_span.h"
#include "opentelemetry/trace/scope.h"
#include "opentelemetry/trace/span.h"
#include "opentelemetry/trace/span_context_kv_iterable_view.h"
#include "opentelemetry/trace/span_startoptions.h"
#include "opentelemetry/version.h"

#include <chrono>

OPENTELEMETRY_BEGIN_NAMESPACE
namespace trace
{

/**
* Handles span creation and in-process context propagation.
*
Expand Down
16 changes: 12 additions & 4 deletions exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -569,8 +569,15 @@ class Tracer : public trace::Tracer
// Parent Context:
// - either use current span
// - or attach to parent SpanContext specified in options
const auto parentContext =
(options.parent.IsValid()) ? options.parent : GetCurrentSpan()->GetContext();
trace::SpanContext parentContext = GetCurrentSpan()->GetContext();
if (nostd::holds_alternative<trace::SpanContext>(options.parent))
{
auto span_context = nostd::get<trace::SpanContext>(options.parent);
if (span_context.IsValid())
{
parentContext = span_context;
}
}

// Populate Etw.RelatedActivityId at envelope level if enabled
GUID RelatedActivityId;
Expand Down Expand Up @@ -1089,8 +1096,9 @@ class TracerProvider : public trace::TracerProvider
// identifier, see EventActivityIdControl.
GetOption(options, "enableActivityId", config_.enableActivityId, false);

// Map parent `SpanId` to RelatedActivityId - Activity identifier from the previous component.
// Use this parameter to link your component's events to the previous component's events.
// Map parent `SpanId` to RelatedActivityId - Activity identifier from the previous
// component. Use this parameter to link your component's events to the previous component's
// events.
GetOption(options, "enableRelatedActivityId", config_.enableRelatedActivityId, false);

// When a new Span is started, the current span automatically becomes its parent.
Expand Down
8 changes: 6 additions & 2 deletions exporters/otlp/test/otlp_http_exporter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,9 @@ TEST_F(OtlpHttpExporterTestPeer, ExportJsonIntegrationTest)
child_span->End();
parent_span->End();

child_span_opts.parent.trace_id().ToLowerBase16(MakeSpan(trace_id_hex));
nostd::get<opentelemetry::trace::SpanContext>(child_span_opts.parent)
.trace_id()
.ToLowerBase16(MakeSpan(trace_id_hex));
report_trace_id.assign(trace_id_hex, sizeof(trace_id_hex));
}

Expand Down Expand Up @@ -282,7 +284,9 @@ TEST_F(OtlpHttpExporterTestPeer, ExportBinaryIntegrationTest)
child_span->End();
parent_span->End();

child_span_opts.parent.trace_id().CopyBytesTo(MakeSpan(trace_id_binary));
nostd::get<opentelemetry::trace::SpanContext>(child_span_opts.parent)
.trace_id()
.CopyBytesTo(MakeSpan(trace_id_binary));
report_trace_id.assign(reinterpret_cast<char *>(trace_id_binary), sizeof(trace_id_binary));
}

Expand Down
22 changes: 20 additions & 2 deletions sdk/src/trace/tracer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "opentelemetry/context/runtime_context.h"
#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/sdk/common/atomic_shared_ptr.h"
#include "opentelemetry/trace/context.h"
#include "opentelemetry/version.h"
#include "src/trace/span.h"

Expand All @@ -27,8 +28,25 @@ nostd::shared_ptr<trace_api::Span> Tracer::StartSpan(
const trace_api::SpanContextKeyValueIterable &links,
const trace_api::StartSpanOptions &options) noexcept
{
trace_api::SpanContext parent_context =
options.parent.IsValid() ? options.parent : GetCurrentSpan()->GetContext();
trace_api::SpanContext parent_context = GetCurrentSpan()->GetContext();
if (nostd::holds_alternative<trace_api::SpanContext>(options.parent))
{
auto span_context = nostd::get<trace_api::SpanContext>(options.parent);
if (span_context.IsValid())
{
parent_context = span_context;
}
}
else if (nostd::holds_alternative<context::Context>(options.parent))
{
auto context = nostd::get<context::Context>(options.parent);
// fetch span context from parent span stored in the context
auto span_context = opentelemetry::trace::GetSpan(context)->GetContext();
if (span_context.IsValid())
{
parent_context = span_context;
}
}

trace_api::TraceId trace_id;
trace_api::SpanId span_id = GetIdGenerator().GenerateSpanId();
Expand Down
39 changes: 39 additions & 0 deletions sdk/test/trace/tracer_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "opentelemetry/sdk/trace/samplers/parent.h"
#include "opentelemetry/sdk/trace/simple_processor.h"
#include "opentelemetry/sdk/trace/span_data.h"
#include "opentelemetry/trace/context.h"

#include <gtest/gtest.h>

Expand Down Expand Up @@ -621,6 +622,44 @@ TEST(Tracer, ExpectParent)
EXPECT_EQ(spandata_second->GetSpanId(), spandata_third->GetParentSpanId());
}

TEST(Tracer, ExpectParentAsContext)
{
std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
auto tracer = initTracer(std::move(exporter));
auto spans = span_data.get()->GetSpans();

ASSERT_EQ(0, spans.size());

auto span_first = tracer->StartSpan("span 1");

opentelemetry::context::Context c1;
auto c2 = trace_api::SetSpan(c1, span_first);
trace_api::StartSpanOptions options;
options.parent = c2;
auto span_second = tracer->StartSpan("span 2", options);

auto c3 = trace_api::SetSpan(c2, span_second);
options.parent = c3;
auto span_third = tracer->StartSpan("span 3", options);

span_third->End();
span_second->End();
span_first->End();

spans = span_data->GetSpans();
ASSERT_EQ(3, spans.size());
auto spandata_first = std::move(spans.at(2));
auto spandata_second = std::move(spans.at(1));
auto spandata_third = std::move(spans.at(0));
EXPECT_EQ("span 1", spandata_first->GetName());
EXPECT_EQ("span 2", spandata_second->GetName());
EXPECT_EQ("span 3", spandata_third->GetName());

EXPECT_EQ(spandata_first->GetSpanId(), spandata_second->GetParentSpanId());
EXPECT_EQ(spandata_second->GetSpanId(), spandata_third->GetParentSpanId());
}

TEST(Tracer, ValidTraceIdToSampler)
{
std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
Expand Down