Skip to content

Commit 5e4e95d

Browse files
committed
feat: send knuth sampling rates tags
Changes: - Set `_dd.p.ksr` tag with the knuth sampling rates computed. - Remove remaining devs from sampling delegation. - Add unit tests.
1 parent 286d0e3 commit 5e4e95d

File tree

6 files changed

+75
-34
lines changed

6 files changed

+75
-34
lines changed

src/datadog/tags.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ const std::string trace_id_high = "_dd.p.tid";
2929
const std::string process_id = "process_id";
3030
const std::string language = "language";
3131
const std::string runtime_id = "runtime-id";
32-
const std::string sampling_decider = "_dd.is_sampling_decider";
3332
const std::string w3c_parent_id = "_dd.parent_id";
3433
const std::string trace_source = "_dd.p.ts";
3534
const std::string apm_enabled = "_dd.apm.enabled";
35+
const std::string ksr = "_dd.p.ksr";
3636

3737
} // namespace internal
3838

src/datadog/tags.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ extern const std::string trace_id_high;
3737
extern const std::string process_id;
3838
extern const std::string language;
3939
extern const std::string runtime_id;
40-
extern const std::string sampling_decider;
4140
extern const std::string w3c_parent_id;
4241
extern const std::string trace_source; // _dd.p.ts
4342
extern const std::string apm_enabled; // _dd.apm.enabled
43+
extern const std::string ksr; // _dd.p.ksr
4444

4545
} // namespace internal
4646

src/datadog/trace_segment.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <datadog/trace_segment.h>
1212

1313
#include <cassert>
14+
#include <charconv>
1415
#include <string>
1516
#include <unordered_map>
1617
#include <utility>
@@ -226,13 +227,6 @@ void TraceSegment::span_finished() {
226227
}
227228
}
228229

229-
if (decision.origin == SamplingDecision::Origin::DELEGATED &&
230-
local_root.parent_id == 0) {
231-
// Convey the fact that, even though we are the root service, we delegated
232-
// the sampling decision and so are not the "sampling decider."
233-
local_root.tags[tags::internal::sampling_decider] = "0";
234-
}
235-
236230
// RFC seems to only mandate that this be set if the trace is kept.
237231
// However, system-tests expect this to be always be set.
238232
// Add it all the time; can't hurt
@@ -292,6 +286,10 @@ void TraceSegment::make_sampling_decision_if_null() {
292286
sampling_decision_ = trace_sampler_->decide(local_root);
293287

294288
update_decision_maker_trace_tag();
289+
290+
trace_tags_.emplace_back(
291+
tags::internal::ksr,
292+
std::to_string(*sampling_decision_->configured_rate));
295293
}
296294

297295
void TraceSegment::update_decision_maker_trace_tag() {

test/test_span.cpp

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,9 @@ TEST_SPAN("injection") {
499499
REQUIRE(writer.items.empty() == false);
500500

501501
// Consume the span that MUST be kept for service liveness.
502-
{ apm_disabled_tracer.create_span(); }
502+
{
503+
apm_disabled_tracer.create_span();
504+
}
503505

504506
auto span = apm_disabled_tracer.create_span();
505507

@@ -784,8 +786,8 @@ TEST_SPAN("injecting W3C tracestate header") {
784786
{"x-datadog-parent-id", "1"},
785787
{"x-datadog-origin", "France"},
786788
},
787-
// The "s:-1" comes from the 0% sample rate.
788-
"dd=s:-1;p:$parent_id;o:France"},
789+
// The "s:-1" and "t.ksr:0.000000" comes from the 0% sample rate.
790+
"dd=s:-1;p:$parent_id;o:France;t.ksr:0.000000"},
789791

790792
{__LINE__,
791793
"trace tags",
@@ -794,8 +796,8 @@ TEST_SPAN("injecting W3C tracestate header") {
794796
{"x-datadog-parent-id", "1"},
795797
{"x-datadog-tags", "_dd.p.foo=x,_dd.p.bar=y,ignored=wrong_prefix"},
796798
},
797-
// The "s:-1" comes from the 0% sample rate.
798-
"dd=s:-1;p:$parent_id;t.foo:x;t.bar:y"},
799+
// The "s:-1" and "t.ksr:0.000000" comes from the 0% sample rate.
800+
"dd=s:-1;p:$parent_id;t.foo:x;t.bar:y;t.ksr:0.000000"},
799801

800802
{__LINE__,
801803
"extra fields",
@@ -815,15 +817,18 @@ TEST_SPAN("injecting W3C tracestate header") {
815817
// The "s:0" comes from the sampling decision in `traceparent_drop`.
816818
"dd=s:0;p:$parent_id;o:France;t.foo:x;t.bar:y;foo:bar;boing:boing"},
817819

818-
{__LINE__,
819-
"replace invalid characters in origin",
820-
{
821-
{"x-datadog-trace-id", "1"},
822-
{"x-datadog-parent-id", "1"},
823-
{"x-datadog-origin", "France, is a country=nation; so is 台北."},
824-
},
825-
// The "s:-1" comes from the 0% sample rate.
826-
"dd=s:-1;p:$parent_id;o:France_ is a country~nation_ so is ______."},
820+
{
821+
__LINE__,
822+
"replace invalid characters in origin",
823+
{
824+
{"x-datadog-trace-id", "1"},
825+
{"x-datadog-parent-id", "1"},
826+
{"x-datadog-origin", "France, is a country=nation; so is 台北."},
827+
},
828+
// The "s:-1" comes from the 0% sample rate.
829+
"dd=s:-1;p:$parent_id;o:France_ is a country~nation_ so is "
830+
"______.;t.ksr:0.000000",
831+
},
827832

828833
{__LINE__,
829834
"replace invalid characters in trace tag key",
@@ -833,7 +838,7 @@ TEST_SPAN("injecting W3C tracestate header") {
833838
{"x-datadog-tags", "_dd.p.a;d台北x =foo,_dd.p.ok=bar"},
834839
},
835840
// The "s:-1" comes from the 0% sample rate.
836-
"dd=s:-1;p:$parent_id;t.a_d______x_:foo;t.ok:bar"},
841+
"dd=s:-1;p:$parent_id;t.a_d______x_:foo;t.ok:bar;t.ksr:0.000000"},
837842

838843
{__LINE__,
839844
"replace invalid characters in trace tag value",
@@ -843,7 +848,8 @@ TEST_SPAN("injecting W3C tracestate header") {
843848
{"x-datadog-tags", "_dd.p.wacky=hello fr~d; how are คุณ?"},
844849
},
845850
// The "s:-1" comes from the 0% sample rate.
846-
"dd=s:-1;p:$parent_id;t.wacky:hello fr_d_ how are _________?"},
851+
"dd=s:-1;p:$parent_id;t.wacky:hello fr_d_ how are "
852+
"_________?;t.ksr:0.000000"},
847853

848854
{__LINE__,
849855
"replace equal signs with tildes in trace tag value",
@@ -853,7 +859,7 @@ TEST_SPAN("injecting W3C tracestate header") {
853859
{"x-datadog-tags", "_dd.p.base64_thingy=d2Fra2EhIHdhaw=="},
854860
},
855861
// The "s:-1" comes from the 0% sample rate.
856-
"dd=s:-1;p:$parent_id;t.base64_thingy:d2Fra2EhIHdhaw~~"},
862+
"dd=s:-1;p:$parent_id;t.base64_thingy:d2Fra2EhIHdhaw~~;t.ksr:0.000000"},
857863

858864
{__LINE__,
859865
"oversized origin truncates it and subsequent fields",

test/test_trace_segment.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,9 @@ TEST_CASE("TraceSegment finalization of spans") {
236236
{"x-datadog-sampling-priority", std::to_string(sampling_priority)},
237237
};
238238
MockDictReader reader{headers};
239-
{ auto span = tracer.extract_span(reader); }
239+
{
240+
auto span = tracer.extract_span(reader);
241+
}
240242
REQUIRE(collector->span_count() == 1);
241243
REQUIRE(collector->first_span().numeric_tags.at(
242244
tags::internal::sampling_priority) == sampling_priority);
@@ -310,6 +312,7 @@ TEST_CASE("TraceSegment finalization of spans") {
310312
REQUIRE_THAT(span.tags, ContainsSubset(filtered));
311313
// "_dd.p.dm" will be added, because we made a sampling decision.
312314
REQUIRE(span.tags.count("_dd.p.dm") == 1);
315+
REQUIRE(span.tags.count("_dd.p.ksr") == 1);
313316
}
314317

315318
SECTION("rate tags") {
@@ -324,6 +327,7 @@ TEST_CASE("TraceSegment finalization of spans") {
324327
REQUIRE(collector->span_count() == 1);
325328
const auto& span = collector->first_span();
326329
REQUIRE(span.numeric_tags.at(tags::internal::agent_sample_rate) == 1.0);
330+
REQUIRE(span.tags.at(tags::internal::ksr) == "1.000000");
327331
}
328332

329333
SECTION(
@@ -343,17 +347,24 @@ TEST_CASE("TraceSegment finalization of spans") {
343347
auto span = tracer.create_span();
344348
(void)span;
345349
}
346-
REQUIRE(collector_response->span_count() == 1);
350+
{
351+
REQUIRE(collector_response->span_count() == 1);
352+
const auto& span = collector_response->first_span();
353+
CHECK(span.tags.at(tags::internal::ksr) == "1.000000");
354+
}
347355

348356
collector_response->chunks.clear();
349357
// Second trace will use the rate from `collector->response`.
350358
{
351359
auto span = tracer.create_span();
352360
(void)span;
353361
}
354-
REQUIRE(collector_response->span_count() == 1);
355-
const auto& span = collector_response->first_span();
356-
REQUIRE(span.numeric_tags.at(tags::internal::agent_sample_rate) == 1.0);
362+
{
363+
REQUIRE(collector_response->span_count() == 1);
364+
const auto& span = collector_response->first_span();
365+
CHECK(span.numeric_tags.at(tags::internal::agent_sample_rate) == 1.0);
366+
CHECK(span.tags.at(tags::internal::ksr) == "1.000000");
367+
}
357368
}
358369

359370
SECTION("rules (implicit and explicit)") {
@@ -383,6 +394,7 @@ TEST_CASE("TraceSegment finalization of spans") {
383394
const auto& span = collector->first_span();
384395
REQUIRE(span.numeric_tags.at(tags::internal::rule_sample_rate) ==
385396
sample_rate);
397+
CHECK(span.tags.at(tags::internal::ksr) == std::to_string(sample_rate));
386398
if (sample_rate == 1.0) {
387399
REQUIRE(span.numeric_tags.at(
388400
tags::internal::rule_limiter_sample_rate) == 1.0);

test/test_tracer.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -995,11 +995,13 @@ TEST_TRACER("span extraction") {
995995
__LINE__,
996996
"origin, trace tags, parent, and extra fields",
997997
traceparent_drop, // traceparent
998-
"dd=o:France;p:00000000000d69ac;t.foo:thing1;t.bar:thing2;x:wow;y:"
998+
"dd=o:France;p:00000000000d69ac;t.ksr:0.728;t.foo:thing1;t.bar:"
999+
"thing2;x:wow;y:"
9991000
"wow", // tracestate
10001001
0, // expected_sampling_priority
10011002
"France", // expected_origin
10021003
{
1004+
{"_dd.p.ksr", "0.728"},
10031005
{"_dd.p.foo", "thing1"},
10041006
{"_dd.p.bar", "thing2"},
10051007
}, // expected_trace_tags
@@ -1844,7 +1846,9 @@ TEST_TRACER("APM tracing disabled") {
18441846
auto finalized_config = finalize_config(config, clock);
18451847
REQUIRE(finalized_config);
18461848
Tracer tracer{*finalized_config};
1847-
{ auto root1 = tracer.create_span(); }
1849+
{
1850+
auto root1 = tracer.create_span();
1851+
}
18481852
REQUIRE(collector->chunks.size() == 1);
18491853
REQUIRE(collector->chunks.front().size() == 1);
18501854

@@ -1923,7 +1927,9 @@ TEST_TRACER("APM tracing disabled") {
19231927

19241928
// When APM Tracing is disabled, we allow one trace per second for service
19251929
// liveness. To ensure consistency, consume the limiter slot.
1926-
{ tracer.create_span(); }
1930+
{
1931+
tracer.create_span();
1932+
}
19271933
collector->chunks.clear();
19281934

19291935
// Case 1: extracted context with priority, but no `_dd.p.ts` → depends if
@@ -2034,3 +2040,22 @@ TEST_TRACER("APM tracing disabled") {
20342040
}
20352041
}
20362042
}
2043+
2044+
TEST_TRACER("_dd.p.ksr is NOT set when overriding the sampling decision") {
2045+
const auto collector = std::make_shared<MockCollector>();
2046+
2047+
TracerConfig config;
2048+
config.collector = collector;
2049+
auto finalized_config = finalize_config(config);
2050+
REQUIRE(finalized_config);
2051+
2052+
Tracer tracer{*finalized_config};
2053+
2054+
{
2055+
auto span = tracer.create_span();
2056+
span.trace_segment().override_sampling_priority(10);
2057+
}
2058+
2059+
auto c = collector->first_span();
2060+
CHECK(c.tags.count(tags::internal::ksr) == 0);
2061+
}

0 commit comments

Comments
 (0)