diff --git a/src/datadog/trace_segment.cpp b/src/datadog/trace_segment.cpp index 61450863..07ce49cf 100644 --- a/src/datadog/trace_segment.cpp +++ b/src/datadog/trace_segment.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -321,9 +322,18 @@ void TraceSegment::make_sampling_decision_if_null() { update_decision_maker_trace_tag(); - trace_tags_.emplace_back( - tags::internal::ksr, - std::to_string(*sampling_decision_->configured_rate)); + // Only set ksr when the sampling mechanism is explicit (agent rate, rule, or + // remote rule). The DEFAULT mechanism means we haven't received any + // configuration from the agent yet, so ksr would be meaningless. + if (sampling_decision_->mechanism && + *sampling_decision_->mechanism != int(SamplingMechanism::DEFAULT)) { + std::array buf; + const auto [ptr, ec] = std::to_chars(buf.data(), buf.data() + buf.size(), + *sampling_decision_->configured_rate, + std::chars_format::general, 6); + assert(ec == std::errc()); + trace_tags_.emplace_back(tags::internal::ksr, std::string(buf.data(), ptr)); + } } void TraceSegment::update_decision_maker_trace_tag() { diff --git a/test/test_span.cpp b/test/test_span.cpp index bce0d27d..65a79c30 100644 --- a/test/test_span.cpp +++ b/test/test_span.cpp @@ -784,8 +784,8 @@ TEST_SPAN("injecting W3C tracestate header") { {"x-datadog-parent-id", "1"}, {"x-datadog-origin", "France"}, }, - // The "s:-1" and "t.ksr:0.000000" comes from the 0% sample rate. - "dd=s:-1;p:$parent_id;o:France;t.ksr:0.000000"}, + // The "s:-1" and "t.ksr:0" comes from the 0% sample rate. + "dd=s:-1;p:$parent_id;o:France;t.ksr:0"}, {__LINE__, "trace tags", @@ -794,8 +794,8 @@ TEST_SPAN("injecting W3C tracestate header") { {"x-datadog-parent-id", "1"}, {"x-datadog-tags", "_dd.p.foo=x,_dd.p.bar=y,ignored=wrong_prefix"}, }, - // The "s:-1" and "t.ksr:0.000000" comes from the 0% sample rate. - "dd=s:-1;p:$parent_id;t.foo:x;t.bar:y;t.ksr:0.000000"}, + // The "s:-1" and "t.ksr:0" comes from the 0% sample rate. + "dd=s:-1;p:$parent_id;t.foo:x;t.bar:y;t.ksr:0"}, {__LINE__, "extra fields", @@ -825,7 +825,7 @@ TEST_SPAN("injecting W3C tracestate header") { }, // The "s:-1" comes from the 0% sample rate. "dd=s:-1;p:$parent_id;o:France_ is a country~nation_ so is " - "______.;t.ksr:0.000000", + "______.;t.ksr:0", }, {__LINE__, @@ -836,7 +836,7 @@ TEST_SPAN("injecting W3C tracestate header") { {"x-datadog-tags", "_dd.p.a;d台北x =foo,_dd.p.ok=bar"}, }, // The "s:-1" comes from the 0% sample rate. - "dd=s:-1;p:$parent_id;t.a_d______x_:foo;t.ok:bar;t.ksr:0.000000"}, + "dd=s:-1;p:$parent_id;t.a_d______x_:foo;t.ok:bar;t.ksr:0"}, {__LINE__, "replace invalid characters in trace tag value", @@ -847,7 +847,7 @@ TEST_SPAN("injecting W3C tracestate header") { }, // The "s:-1" comes from the 0% sample rate. "dd=s:-1;p:$parent_id;t.wacky:hello fr_d_ how are " - "_________?;t.ksr:0.000000"}, + "_________?;t.ksr:0"}, {__LINE__, "replace equal signs with tildes in trace tag value", @@ -857,7 +857,7 @@ TEST_SPAN("injecting W3C tracestate header") { {"x-datadog-tags", "_dd.p.base64_thingy=d2Fra2EhIHdhaw=="}, }, // The "s:-1" comes from the 0% sample rate. - "dd=s:-1;p:$parent_id;t.base64_thingy:d2Fra2EhIHdhaw~~;t.ksr:0.000000"}, + "dd=s:-1;p:$parent_id;t.base64_thingy:d2Fra2EhIHdhaw~~;t.ksr:0"}, {__LINE__, "oversized origin truncates it and subsequent fields", diff --git a/test/test_trace_segment.cpp b/test/test_trace_segment.cpp index 94d167e6..8da35261 100644 --- a/test/test_trace_segment.cpp +++ b/test/test_trace_segment.cpp @@ -7,7 +7,9 @@ #include #include +#include #include +#include #include #include "matchers.h" @@ -310,7 +312,9 @@ TEST_CASE("TraceSegment finalization of spans") { REQUIRE_THAT(span.tags, ContainsSubset(filtered)); // "_dd.p.dm" will be added, because we made a sampling decision. REQUIRE(span.tags.count("_dd.p.dm") == 1); - REQUIRE(span.tags.count("_dd.p.ksr") == 1); + // "_dd.p.ksr" is NOT set because this uses the DEFAULT mechanism (no + // agent configuration received yet). + REQUIRE(span.tags.count("_dd.p.ksr") == 0); } SECTION("rate tags") { @@ -325,7 +329,8 @@ TEST_CASE("TraceSegment finalization of spans") { REQUIRE(collector->span_count() == 1); const auto& span = collector->first_span(); REQUIRE(span.numeric_tags.at(tags::internal::agent_sample_rate) == 1.0); - REQUIRE(span.tags.at(tags::internal::ksr) == "1.000000"); + // ksr is NOT set for the DEFAULT mechanism. + REQUIRE(span.tags.count(tags::internal::ksr) == 0); } SECTION( @@ -348,7 +353,8 @@ TEST_CASE("TraceSegment finalization of spans") { { REQUIRE(collector_response->span_count() == 1); const auto& span = collector_response->first_span(); - CHECK(span.tags.at(tags::internal::ksr) == "1.000000"); + // ksr is NOT set for the DEFAULT mechanism. + CHECK(span.tags.count(tags::internal::ksr) == 0); } collector_response->chunks.clear(); @@ -361,7 +367,7 @@ TEST_CASE("TraceSegment finalization of spans") { REQUIRE(collector_response->span_count() == 1); const auto& span = collector_response->first_span(); CHECK(span.numeric_tags.at(tags::internal::agent_sample_rate) == 1.0); - CHECK(span.tags.at(tags::internal::ksr) == "1.000000"); + CHECK(span.tags.at(tags::internal::ksr) == "1"); } } @@ -392,7 +398,11 @@ TEST_CASE("TraceSegment finalization of spans") { const auto& span = collector->first_span(); REQUIRE(span.numeric_tags.at(tags::internal::rule_sample_rate) == sample_rate); - CHECK(span.tags.at(tags::internal::ksr) == std::to_string(sample_rate)); + { + char buf[32]; + std::snprintf(buf, sizeof(buf), "%.6g", sample_rate); + CHECK(span.tags.at(tags::internal::ksr) == std::string(buf)); + } if (sample_rate == 1.0) { REQUIRE(span.numeric_tags.at( tags::internal::rule_limiter_sample_rate) == 1.0);