diff --git a/api/include/opentelemetry/trace/span_context.h b/api/include/opentelemetry/trace/span_context.h index 57b6a72e2e..aed22cfe72 100644 --- a/api/include/opentelemetry/trace/span_context.h +++ b/api/include/opentelemetry/trace/span_context.h @@ -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_; } @@ -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; }; diff --git a/api/test/trace/span_context_test.cc b/api/test/trace/span_context_test.cc index 661bba00bc..b364348ccd 100644 --- a/api/test/trace/span_context_test.cc +++ b/api/test/trace/span_context_test.cc @@ -1,4 +1,6 @@ #include "opentelemetry/trace/span_context.h" +#include "opentelemetry/trace/span_id.h" +#include "opentelemetry/trace/trace_id.h" #include @@ -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()); +} diff --git a/sdk/src/trace/BUILD b/sdk/src/trace/BUILD index 49699e4c44..221066076b 100644 --- a/sdk/src/trace/BUILD +++ b/sdk/src/trace/BUILD @@ -22,5 +22,6 @@ cc_library( deps = [ "//api", "//sdk:headers", + "//sdk/src/common:random", ], ) diff --git a/sdk/src/trace/CMakeLists.txt b/sdk/src/trace/CMakeLists.txt index 5d7c8777f1..9f9e06f45c 100644 --- a/sdk/src/trace/CMakeLists.txt +++ b/sdk/src/trace/CMakeLists.txt @@ -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) diff --git a/sdk/src/trace/span.cc b/sdk/src/trace/span.cc index 0e465edd5a..c6c3151a7f 100644 --- a/sdk/src/trace/span.cc +++ b/sdk/src/trace/span.cc @@ -1,4 +1,5 @@ #include "src/trace/span.h" +#include "src/common/random.h" #include "opentelemetry/context/runtime_context.h" #include "opentelemetry/version.h" @@ -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, std::shared_ptr 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()}, @@ -59,7 +77,19 @@ Span::Span(std::shared_ptr &&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; }); @@ -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 lock_guard{mu_}; diff --git a/sdk/src/trace/span.h b/sdk/src/trace/span.h index f307aa5c53..24af0256e5 100644 --- a/sdk/src/trace/span.h +++ b/sdk/src/trace/span.h @@ -19,7 +19,8 @@ class Span final : public trace_api::Span std::shared_ptr 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; diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 0221d35003..3923a47161 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -47,8 +47,13 @@ nostd::shared_ptr Tracer::StartSpan( } else { - auto span = nostd::shared_ptr{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. + const trace_api::SpanContext kInvalidParentSpanContext(false, false); + + auto span = nostd::shared_ptr{ + new (std::nothrow) Span{this->shared_from_this(), processor_.load(), name, attributes, + options, kInvalidParentSpanContext}}; span->SetToken( nostd::unique_ptr(new context::Token(context::RuntimeContext::Attach( diff --git a/sdk/test/trace/CMakeLists.txt b/sdk/test/trace/CMakeLists.txt index 69ad1c749b..c72cd7fe77 100644 --- a/sdk/test/trace/CMakeLists.txt +++ b/sdk/test/trace/CMakeLists.txt @@ -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() diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index aebab0de3d..efdc6b6f8b 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -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)