From d6301b7c2b21d8a0faf7ff340e50e83850b24fa9 Mon Sep 17 00:00:00 2001 From: Marc Alff Date: Mon, 17 Nov 2025 19:18:12 +0100 Subject: [PATCH] [SDK] Reset TraceFlags::IsSampled bit on sampler Decision::DROP (#3745) --- CHANGELOG.md | 3 + api/include/opentelemetry/trace/trace_flags.h | 2 +- sdk/src/trace/tracer.cc | 4 ++ sdk/test/trace/tracer_test.cc | 71 +++++++++++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e02d24d24..a10ab8c4d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,9 @@ Increment the: * [CI] Free disk space [#3749](https://github.com/open-telemetry/opentelemetry-cpp/pull/3749) +* [SDK] Reset TraceFlags::IsSampled bit on sampler Decision::DROP + [#3745](https://github.com/open-telemetry/opentelemetry-cpp/pull/3745) + New Features: * [CONFIGURATION] Implement declarative configuration (config.yaml) diff --git a/api/include/opentelemetry/trace/trace_flags.h b/api/include/opentelemetry/trace/trace_flags.h index 0ad9dc136b..f4c7bc6a44 100644 --- a/api/include/opentelemetry/trace/trace_flags.h +++ b/api/include/opentelemetry/trace/trace_flags.h @@ -29,7 +29,7 @@ class TraceFlags final /** * Valid flags in W3C Trace Context version 2. - * See https://www.w3.org/TR/trace-context-1/#trace-flags + * See https://www.w3.org/TR/trace-context-2/#trace-flags */ static constexpr uint8_t kAllW3CTraceContext2Flags = kIsSampled | kIsRandom; diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 263638955b..4a689bbcd7 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -116,6 +116,10 @@ nostd::shared_ptr Tracer::StartSpan( { flags |= opentelemetry::trace::TraceFlags::kIsSampled; } + else + { + flags &= ~opentelemetry::trace::TraceFlags::kIsSampled; + } #if 1 /* https://github.com/open-telemetry/opentelemetry-specification as of v1.29.0 */ diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index 6e70c0130e..cec1bf496d 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -107,6 +107,48 @@ class MockSampler final : public Sampler nostd::string_view GetDescription() const noexcept override { return "MockSampler"; } }; +/** + * A mock sampler with ShouldSample returning + * a decision based on the span name. + */ +class MockDecisionSampler final : public Sampler +{ +public: + SamplingResult ShouldSample( + const SpanContext & /*parent_context*/, + trace_api::TraceId /*trace_id*/, + nostd::string_view name, + trace_api::SpanKind /*span_kind*/, + const opentelemetry::common::KeyValueIterable & /*attributes*/, + const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/) noexcept override + { + std::string span_name{name}; + + if (span_name.find("DROP-") != std::string::npos) + { + return {Decision::DROP, + nostd::unique_ptr>( + nullptr), + nostd::shared_ptr(nullptr)}; + } + + if (span_name.find("RECORD_ONLY-") != std::string::npos) + { + return {Decision::RECORD_ONLY, + nostd::unique_ptr>( + nullptr), + nostd::shared_ptr(nullptr)}; + } + + return {Decision::RECORD_AND_SAMPLE, + nostd::unique_ptr>( + nullptr), + nostd::shared_ptr(nullptr)}; + } + + nostd::string_view GetDescription() const noexcept override { return "MockDecisionSampler"; } +}; + /** * A Mock Custom ID Generator */ @@ -1331,3 +1373,32 @@ TEST(Tracer, SpanCleanupWithScope) } EXPECT_EQ(4, span_data->GetSpans().size()); } + +TEST(Tracer, SpanSamplerDecision) +{ + InMemorySpanExporter *exporter = new InMemorySpanExporter(); + std::shared_ptr span_data = exporter->GetData(); + auto tracer = initTracer(std::unique_ptr{exporter}, new MockDecisionSampler()); + { + auto span0 = tracer->StartSpan("Span0"); + auto span1 = tracer->StartSpan("span1"); + auto context1 = span1->GetContext(); + EXPECT_TRUE(context1.IsValid()); + EXPECT_TRUE(context1.IsSampled()); + { + trace_api::Scope scope1(span1); + auto span2 = tracer->StartSpan("RECORD_ONLY-span2"); + auto context2 = span2->GetContext(); + EXPECT_TRUE(context2.IsValid()); + EXPECT_FALSE(context2.IsSampled()); + { + trace_api::Scope scope2(span2); + auto span3 = tracer->StartSpan("DROP-span3"); + auto context3 = span3->GetContext(); + EXPECT_TRUE(context3.IsValid()); + EXPECT_FALSE(context3.IsSampled()); + } + } + } + EXPECT_EQ(3, span_data->GetSpans().size()); +}