Skip to content
Merged
15 changes: 14 additions & 1 deletion api/include/opentelemetry/trace/span_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,22 @@ class SpanContext final
{
public:
/* A temporary constructor for an invalid SpanContext.
* Trace id and span id are set to invalid (all zeros).
*
* @param sampled_flag a required parameter specifying if child spans should be
* sampled
* @param has_remote_parent a required parameter specifying if this context has
* a remote parent
*/
SpanContext(bool sampled_flag, bool has_remote_parent)
: trace_flags_(trace_api::TraceFlags((uint8_t)sampled_flag)),
: trace_id_(),
span_id_(),
trace_flags_(trace_api::TraceFlags((uint8_t)sampled_flag)),
remote_parent_(has_remote_parent){};

// @returns whether this context is valid
bool IsValid() const noexcept { return trace_id_.IsValid() && span_id_.IsValid(); }

// @returns the trace_flags associated with this span_context
const trace_api::TraceFlags &trace_flags() const noexcept { return trace_flags_; }

Expand All @@ -52,7 +59,13 @@ class SpanContext final
// @returns whether this context has a remote parent or not
bool HasRemoteParent() const noexcept { return remote_parent_; }

const TraceId &trace_id() const noexcept { return trace_id_; }

const SpanId &span_id() const noexcept { return span_id_; }

private:
const TraceId trace_id_;
const SpanId span_id_;
const trace_api::TraceFlags trace_flags_;
const bool remote_parent_ = false;
};
Expand Down
13 changes: 13 additions & 0 deletions api/test/trace/span_context_test.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "opentelemetry/trace/span_context.h"
#include "opentelemetry/trace/span_id.h"
#include "opentelemetry/trace/trace_id.h"

#include <gtest/gtest.h>

Expand Down Expand Up @@ -36,3 +38,14 @@ TEST(SpanContextTest, TraceFlags)

ASSERT_EQ(s2.trace_flags().flags(), 0);
}

// Test that SpanContext is invalid
TEST(SpanContextTest, Invalid)
{
SpanContext s1(false, false);
EXPECT_FALSE(s1.IsValid());

// Test that trace id and span id are invalid
EXPECT_EQ(s1.trace_id(), opentelemetry::trace::TraceId());
EXPECT_EQ(s1.span_id(), opentelemetry::trace::SpanId());
}
1 change: 1 addition & 0 deletions sdk/src/trace/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ cc_library(
deps = [
"//api",
"//sdk:headers",
"//sdk/src/common:random",
],
)
2 changes: 2 additions & 0 deletions sdk/src/trace/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ add_library(
opentelemetry_trace
tracer_provider.cc tracer.cc span.cc batch_span_processor.cc
samplers/parent_or_else.cc samplers/probability.cc)

target_link_libraries(opentelemetry_trace opentelemetry_common)
37 changes: 34 additions & 3 deletions sdk/src/trace/span.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "src/trace/span.h"
#include "src/common/random.h"

#include "opentelemetry/context/runtime_context.h"
#include "opentelemetry/version.h"
Expand Down Expand Up @@ -39,11 +40,28 @@ SteadyTimestamp NowOr(const SteadyTimestamp &steady)
}
} // namespace

// Helper function to generate random trace id.
trace_api::TraceId GenerateRandomTraceId()
{
uint8_t trace_id_buf[trace_api::TraceId::kSize];
sdk::common::Random::GenerateRandomBuffer(trace_id_buf);
return trace_api::TraceId(trace_id_buf);
}

// Helper function to generate random span id.
trace_api::SpanId GenerateRandomSpanId()
{
uint8_t span_id_buf[trace_api::SpanId::kSize];
sdk::common::Random::GenerateRandomBuffer(span_id_buf);
return trace_api::SpanId(span_id_buf);
}

Span::Span(std::shared_ptr<Tracer> &&tracer,
std::shared_ptr<SpanProcessor> processor,
nostd::string_view name,
const trace_api::KeyValueIterable &attributes,
const trace_api::StartSpanOptions &options) noexcept
const trace_api::StartSpanOptions &options,
const trace_api::SpanContext &parent_span_context) noexcept
: tracer_{std::move(tracer)},
processor_{processor},
recordable_{processor_->MakeRecordable()},
Expand All @@ -59,7 +77,19 @@ Span::Span(std::shared_ptr<Tracer> &&tracer,
}
recordable_->SetName(name);

attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept {
if (parent_span_context.IsValid())
{
recordable_->SetIds(parent_span_context.trace_id(), GenerateRandomSpanId(),
parent_span_context.span_id());
}
else
{
recordable_->SetIds(GenerateRandomTraceId(), GenerateRandomSpanId(), trace_api::SpanId());
}
// TODO: Create and populate SpanContext for this span when SpanContext is fully implemented

attributes.ForEachKeyValue([&](nostd::string_view key,
opentelemetry::common::AttributeValue value) noexcept {
recordable_->SetAttribute(key, value);
return true;
});
Expand All @@ -74,7 +104,8 @@ Span::~Span()
End();
}

void Span::SetAttribute(nostd::string_view key, const common::AttributeValue &value) noexcept
void Span::SetAttribute(nostd::string_view key,
const opentelemetry::common::AttributeValue &value) noexcept
{
std::lock_guard<std::mutex> lock_guard{mu_};

Expand Down
3 changes: 2 additions & 1 deletion sdk/src/trace/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class Span final : public trace_api::Span
std::shared_ptr<SpanProcessor> processor,
nostd::string_view name,
const trace_api::KeyValueIterable &attributes,
const trace_api::StartSpanOptions &options) noexcept;
const trace_api::StartSpanOptions &options,
const trace_api::SpanContext &parent_span_context) noexcept;

~Span() override;

Expand Down
9 changes: 7 additions & 2 deletions sdk/src/trace/tracer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,13 @@ nostd::shared_ptr<trace_api::Span> Tracer::StartSpan(
}
else
{
auto span = nostd::shared_ptr<trace_api::Span>{new (std::nothrow) Span{
this->shared_from_this(), processor_.load(), name, attributes, options}};
// TODO: Get parent span context from current context. For now we assume all spans
// have no parent, and pass an invalid parent span context to the Span constructor.
Comment thread
nadiaciobanu marked this conversation as resolved.
const trace_api::SpanContext kInvalidParentSpanContext(false, false);
Comment thread
nadiaciobanu marked this conversation as resolved.

auto span = nostd::shared_ptr<trace_api::Span>{
new (std::nothrow) Span{this->shared_from_this(), processor_.load(), name, attributes,
options, kInvalidParentSpanContext}};

span->SetToken(
nostd::unique_ptr<context::Token>(new context::Token(context::RuntimeContext::Attach(
Expand Down
5 changes: 2 additions & 3 deletions sdk/test/trace/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ foreach(
batch_span_processor_test
attribute_utils_test)
add_executable(${testname} "${testname}.cc")
target_link_libraries(
${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}
opentelemetry_common opentelemetry_trace)
target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT} opentelemetry_trace)
gtest_add_tests(TARGET ${testname} TEST_PREFIX trace. TEST_LIST ${testname})
endforeach()

Expand Down
7 changes: 7 additions & 0 deletions sdk/test/trace/tracer_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,17 @@ TEST(Tracer, ToMockSpanExporter)
ASSERT_EQ(1, spans_received->size());

ASSERT_EQ("span 2", spans_received->at(0)->GetName());
EXPECT_TRUE(spans_received->at(0)->GetTraceId().IsValid());
EXPECT_TRUE(spans_received->at(0)->GetSpanId().IsValid());
EXPECT_FALSE(spans_received->at(0)->GetParentSpanId().IsValid());

span_first->End();
ASSERT_EQ(2, spans_received->size());

ASSERT_EQ("span 1", spans_received->at(1)->GetName());
EXPECT_TRUE(spans_received->at(1)->GetTraceId().IsValid());
EXPECT_TRUE(spans_received->at(1)->GetSpanId().IsValid());
EXPECT_FALSE(spans_received->at(1)->GetParentSpanId().IsValid());
}

TEST(Tracer, StartSpanSampleOn)
Expand Down