diff --git a/sdk/include/opentelemetry/sdk/trace/sampler.h b/sdk/include/opentelemetry/sdk/trace/sampler.h index f44af1057f..d26b33bb97 100644 --- a/sdk/include/opentelemetry/sdk/trace/sampler.h +++ b/sdk/include/opentelemetry/sdk/trace/sampler.h @@ -5,6 +5,7 @@ #include "opentelemetry/trace/span_context.h" #include "opentelemetry/trace/span_context_kv_iterable.h" #include "opentelemetry/trace/trace_id.h" +#include "opentelemetry/trace/trace_state.h" #include "opentelemetry/version.h" #include @@ -41,6 +42,8 @@ struct SamplingResult Decision decision; // A set of span Attributes that will also be added to the Span. Can be nullptr. std::unique_ptr> attributes; + // The tracestate used by the span. + nostd::shared_ptr trace_state; }; /** @@ -61,7 +64,7 @@ class Sampler * @param name the name of the new Span. * @param spanKind the trace_api::SpanKind of the Span. * @param attributes list of AttributeValue with their keys. - * @param links TODO: Collection of links that will be associated with the Span to be created. + * @param links Collection of links that will be associated with the Span to be created. * @return sampling result whether span should be sampled or not. * @since 0.1.0 */ diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h b/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h index f6e3221ce3..6a8b7f5581 100644 --- a/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h +++ b/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h @@ -20,14 +20,21 @@ class AlwaysOffSampler : public Sampler * @return Returns DROP always */ SamplingResult ShouldSample( - const trace_api::SpanContext & /*parent_context*/, + const trace_api::SpanContext &parent_context, trace_api::TraceId /*trace_id*/, nostd::string_view /*name*/, trace_api::SpanKind /*span_kind*/, const opentelemetry::common::KeyValueIterable & /*attributes*/, const trace_api::SpanContextKeyValueIterable & /*links*/) noexcept override { - return {Decision::DROP, nullptr}; + if (!parent_context.IsValid()) + { + return {Decision::DROP, nullptr, opentelemetry::trace::TraceState::GetDefault()}; + } + else + { + return {Decision::DROP, nullptr, parent_context.trace_state()}; + } } /** diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h b/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h index fb5396e206..b717f9bdf7 100644 --- a/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h +++ b/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h @@ -19,14 +19,21 @@ class AlwaysOnSampler : public Sampler * @return Always return Decision RECORD_AND_SAMPLE */ inline SamplingResult ShouldSample( - const trace_api::SpanContext & /*parent_context*/, + const trace_api::SpanContext &parent_context, trace_api::TraceId /*trace_id*/, nostd::string_view /*name*/, trace_api::SpanKind /*span_kind*/, const opentelemetry::common::KeyValueIterable & /*attributes*/, const trace_api::SpanContextKeyValueIterable & /*links*/) noexcept override { - return {Decision::RECORD_AND_SAMPLE, nullptr}; + if (!parent_context.IsValid()) + { + return {Decision::RECORD_AND_SAMPLE, nullptr, opentelemetry::trace::TraceState::GetDefault()}; + } + else + { + return {Decision::RECORD_AND_SAMPLE, nullptr, parent_context.trace_state()}; + } } /** diff --git a/sdk/src/trace/samplers/parent.cc b/sdk/src/trace/samplers/parent.cc index 08095398a8..212a29e3c4 100644 --- a/sdk/src/trace/samplers/parent.cc +++ b/sdk/src/trace/samplers/parent.cc @@ -28,10 +28,10 @@ SamplingResult ParentBasedSampler::ShouldSample( // If parent exists: if (parent_context.IsSampled()) { - return {Decision::RECORD_AND_SAMPLE, nullptr}; + return {Decision::RECORD_AND_SAMPLE, nullptr, parent_context.trace_state()}; } - return {Decision::DROP, nullptr}; + return {Decision::DROP, nullptr, parent_context.trace_state()}; } nostd::string_view ParentBasedSampler::GetDescription() const noexcept diff --git a/sdk/src/trace/span.cc b/sdk/src/trace/span.cc index ca5243fb18..576d54f38c 100644 --- a/sdk/src/trace/span.cc +++ b/sdk/src/trace/span.cc @@ -65,6 +65,7 @@ Span::Span(std::shared_ptr &&tracer, const trace_api::StartSpanOptions &options, const trace_api::SpanContext &parent_span_context, const opentelemetry::sdk::resource::Resource &resource, + const nostd::shared_ptr trace_state, const bool sampled) noexcept : tracer_{std::move(tracer)}, processor_{processor}, @@ -98,8 +99,9 @@ Span::Span(std::shared_ptr &&tracer, trace_id, span_id, sampled ? trace_api::TraceFlags{trace_api::TraceFlags::kIsSampled} : trace_api::TraceFlags{}, false, - is_parent_span_valid ? parent_span_context.trace_state() - : trace_api::TraceState::GetDefault())); + trace_state ? trace_state + : is_parent_span_valid ? parent_span_context.trace_state() + : trace_api::TraceState::GetDefault())); attributes.ForEachKeyValue( [&](nostd::string_view key, opentelemetry::common::AttributeValue value) noexcept { diff --git a/sdk/src/trace/span.h b/sdk/src/trace/span.h index 0f8e843e48..01fb995517 100644 --- a/sdk/src/trace/span.h +++ b/sdk/src/trace/span.h @@ -23,6 +23,8 @@ class Span final : public trace_api::Span const trace_api::StartSpanOptions &options, const trace_api::SpanContext &parent_span_context, const opentelemetry::sdk::resource::Resource &resource, + const nostd::shared_ptr trace_state = + trace_api::TraceState::GetDefault(), const bool sampled = false) noexcept; ~Span() override; diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index b85164b6ac..93fdc6f680 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -73,9 +73,9 @@ nostd::shared_ptr Tracer::StartSpan( } else { - auto span = nostd::shared_ptr{ - new (std::nothrow) Span{this->shared_from_this(), processor_.load(), name, attributes, - links, options, parent, resource_, true}}; + auto span = nostd::shared_ptr{new (std::nothrow) Span{ + this->shared_from_this(), processor_.load(), name, attributes, links, options, parent, + resource_, sampling_result.trace_state, true}}; // if the attributes is not nullptr, add attributes to the span. if (sampling_result.attributes) diff --git a/sdk/test/trace/always_off_sampler_test.cc b/sdk/test/trace/always_off_sampler_test.cc index 822b81f93e..6fea04906d 100644 --- a/sdk/test/trace/always_off_sampler_test.cc +++ b/sdk/test/trace/always_off_sampler_test.cc @@ -27,6 +27,7 @@ TEST(AlwaysOffSampler, ShouldSample) ASSERT_EQ(Decision::DROP, sampling_result.decision); ASSERT_EQ(nullptr, sampling_result.attributes); + ASSERT_EQ("", sampling_result.trace_state->ToHeader()); } TEST(AlwaysOffSampler, GetDescription) diff --git a/sdk/test/trace/always_on_sampler_test.cc b/sdk/test/trace/always_on_sampler_test.cc index 7dad69acc4..9adb5258a5 100644 --- a/sdk/test/trace/always_on_sampler_test.cc +++ b/sdk/test/trace/always_on_sampler_test.cc @@ -34,6 +34,7 @@ TEST(AlwaysOnSampler, ShouldSample) ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision); ASSERT_EQ(nullptr, sampling_result.attributes); + ASSERT_EQ("", sampling_result.trace_state->ToHeader()); // Test with a valid trace id and empty parent context sampling_result = sampler.ShouldSample( @@ -44,6 +45,7 @@ TEST(AlwaysOnSampler, ShouldSample) ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision); ASSERT_EQ(nullptr, sampling_result.attributes); + ASSERT_EQ("", sampling_result.trace_state->ToHeader()); } TEST(AlwaysOnSampler, GetDescription) diff --git a/sdk/test/trace/parent_sampler_test.cc b/sdk/test/trace/parent_sampler_test.cc index ea9718bef5..692a1bf92d 100644 --- a/sdk/test/trace/parent_sampler_test.cc +++ b/sdk/test/trace/parent_sampler_test.cc @@ -31,9 +31,11 @@ TEST(ParentBasedSampler, ShouldSample) opentelemetry::common::KeyValueIterableView view{m1}; trace_api::SpanContextKeyValueIterableView links{l1}; - trace_api::SpanContext parent_context_sampled(trace_id, span_id, trace_api::TraceFlags{1}, false); + auto trace_state = opentelemetry::trace::TraceState::FromHeader("congo=t61rcWkgMzE"); + trace_api::SpanContext parent_context_sampled(trace_id, span_id, trace_api::TraceFlags{1}, false, + trace_state); trace_api::SpanContext parent_context_nonsampled(trace_id, span_id, trace_api::TraceFlags{0}, - false); + false, trace_state); // Case 1: Parent doesn't exist. Return result of delegateSampler() auto sampling_result = sampler_off.ShouldSample(trace_api::SpanContext::GetInvalid(), trace_id, @@ -43,16 +45,20 @@ TEST(ParentBasedSampler, ShouldSample) ASSERT_EQ(Decision::DROP, sampling_result.decision); ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result2.decision); + ASSERT_EQ("", sampling_result.trace_state->ToHeader()); + ASSERT_EQ("", sampling_result2.trace_state->ToHeader()); // Case 2: Parent exists and SampledFlag is true auto sampling_result3 = sampler_off.ShouldSample(parent_context_sampled, trace_id, "", span_kind, view, links); ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result3.decision); + ASSERT_EQ("congo=t61rcWkgMzE", sampling_result3.trace_state->ToHeader()); // Case 3: Parent exists and SampledFlag is false auto sampling_result4 = sampler_on.ShouldSample(parent_context_nonsampled, trace_id, "", span_kind, view, links); ASSERT_EQ(Decision::DROP, sampling_result4.decision); + ASSERT_EQ("congo=t61rcWkgMzE", sampling_result4.trace_state->ToHeader()); } TEST(ParentBasedSampler, GetDescription)