From d2db02c742ffd64753a20f37aaad83973b11a4a9 Mon Sep 17 00:00:00 2001 From: bm1549 Date: Tue, 10 Mar 2026 21:39:14 -0400 Subject: [PATCH 1/2] Add _dd.p.ksr propagated tag for Knuth sampling rate Co-Authored-By: Claude Opus 4.6 --- packages/dd-trace/src/constants.js | 1 + packages/dd-trace/src/priority_sampler.js | 16 +++++- .../dd-trace/test/priority_sampler.spec.js | 57 +++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/packages/dd-trace/src/constants.js b/packages/dd-trace/src/constants.js index 1e7715dda8..2bef6f88ae 100644 --- a/packages/dd-trace/src/constants.js +++ b/packages/dd-trace/src/constants.js @@ -22,6 +22,7 @@ module.exports = { SPAN_SAMPLING_MAX_PER_SECOND: '_dd.span_sampling.max_per_second', DATADOG_LAMBDA_EXTENSION_PATH: '/opt/extensions/datadog-agent', DECISION_MAKER_KEY: '_dd.p.dm', + SAMPLING_KNUTH_RATE: '_dd.p.ksr', PROCESS_ID: 'process_id', ERROR_TYPE: 'error.type', ERROR_MESSAGE: 'error.message', diff --git a/packages/dd-trace/src/priority_sampler.js b/packages/dd-trace/src/priority_sampler.js index 36761ce3d0..0dc58689ce 100644 --- a/packages/dd-trace/src/priority_sampler.js +++ b/packages/dd-trace/src/priority_sampler.js @@ -31,10 +31,21 @@ const { SAMPLING_LIMIT_DECISION, SAMPLING_AGENT_DECISION, DECISION_MAKER_KEY, + SAMPLING_KNUTH_RATE, } = require('./constants') const DEFAULT_KEY = 'service:,env:' +/** + * Formats a sampling rate as a string with up to 6 significant digits and no trailing zeros. + * + * @param {number} rate + * @returns {string} + */ +function formatKnuthRate (rate) { + return Number(rate.toPrecision(6)).toString() +} + const defaultSampler = new Sampler(AUTO_KEEP) /** @@ -254,6 +265,7 @@ class PrioritySampler { */ #getPriorityByRule (context, rule) { context._trace[SAMPLING_RULE_DECISION] = rule.sampleRate + context._trace.tags[SAMPLING_KNUTH_RATE] = formatKnuthRate(rule.sampleRate) context._sampling.mechanism = SAMPLING_MECHANISM_RULE if (rule.provenance === 'customer') context._sampling.mechanism = SAMPLING_MECHANISM_REMOTE_USER if (rule.provenance === 'dynamic') context._sampling.mechanism = SAMPLING_MECHANISM_REMOTE_DYNAMIC @@ -290,7 +302,9 @@ class PrioritySampler { // TODO: Change underscored properties to private ones. const sampler = this._samplers[key] || this._samplers[DEFAULT_KEY] - context._trace[SAMPLING_AGENT_DECISION] = sampler.rate() + const rate = sampler.rate() + context._trace[SAMPLING_AGENT_DECISION] = rate + context._trace.tags[SAMPLING_KNUTH_RATE] = formatKnuthRate(rate) context._sampling.mechanism = sampler === defaultSampler ? SAMPLING_MECHANISM_DEFAULT : SAMPLING_MECHANISM_AGENT diff --git a/packages/dd-trace/test/priority_sampler.spec.js b/packages/dd-trace/test/priority_sampler.spec.js index e9f8c7fdfa..effdcc4e7d 100644 --- a/packages/dd-trace/test/priority_sampler.spec.js +++ b/packages/dd-trace/test/priority_sampler.spec.js @@ -18,6 +18,7 @@ const { SAMPLING_MECHANISM_REMOTE_DYNAMIC, DECISION_MAKER_KEY, SAMPLING_MECHANISM_APPSEC, + SAMPLING_KNUTH_RATE, } = require('../src/constants') const { ASM } = require('../src/standalone/product') @@ -369,6 +370,62 @@ describe('PrioritySampler', () => { assert.strictEqual(context._trace['_dd.limit_psr'], 1) }) + it('should set _dd.p.ksr tag for agent sampling', () => { + prioritySampler.sample(span) + + assert.strictEqual(context._trace.tags[SAMPLING_KNUTH_RATE], '1') + }) + + it('should set _dd.p.ksr tag for agent sampling with custom rate', () => { + prioritySampler.update({ + 'service:test,env:test': 0.5, + }) + prioritySampler.sample(span) + + assert.strictEqual(context._trace.tags[SAMPLING_KNUTH_RATE], '0.5') + }) + + it('should set _dd.p.ksr tag for rule-based sampling', () => { + prioritySampler = new PrioritySampler('test', { + sampleRate: 0.5, + }) + prioritySampler.sample(span) + + assert.strictEqual(context._trace.tags[SAMPLING_KNUTH_RATE], '0.5') + }) + + it('should set _dd.p.ksr tag for rule-based sampling with rate 0', () => { + prioritySampler = new PrioritySampler('test', { + sampleRate: 0, + }) + prioritySampler.sample(span) + + assert.strictEqual(context._trace.tags[SAMPLING_KNUTH_RATE], '0') + }) + + it('should set _dd.p.ksr tag for rate 1.0 as "1"', () => { + prioritySampler = new PrioritySampler('test', { + sampleRate: 1.0, + }) + prioritySampler.sample(span) + + assert.strictEqual(context._trace.tags[SAMPLING_KNUTH_RATE], '1') + }) + + it('should set _dd.p.ksr tag as a string type', () => { + prioritySampler.sample(span) + + assert.strictEqual(typeof context._trace.tags[SAMPLING_KNUTH_RATE], 'string') + }) + + it('should not set _dd.p.ksr tag for manual sampling', () => { + context._tags[MANUAL_KEEP] = undefined + + prioritySampler.sample(context) + + assert.strictEqual(context._trace.tags[SAMPLING_KNUTH_RATE], undefined) + }) + it('should ignore empty span', () => { prioritySampler.sample() prioritySampler.sample() From 8a10db8ef2b9f0df930a1202f4a6b75faad2ddc2 Mon Sep 17 00:00:00 2001 From: bm1549 Date: Tue, 10 Mar 2026 22:42:53 -0400 Subject: [PATCH 2/2] Do not set _dd.p.ksr when default sampling mechanism is used Only set the SAMPLING_KNUTH_RATE (_dd.p.ksr) tag when actual agent rates have been received (SAMPLING_MECHANISM_AGENT), not when using the built-in default sampler (SAMPLING_MECHANISM_DEFAULT). Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/dd-trace/src/priority_sampler.js | 8 ++++++-- packages/dd-trace/test/priority_sampler.spec.js | 9 ++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/dd-trace/src/priority_sampler.js b/packages/dd-trace/src/priority_sampler.js index 0dc58689ce..4e586bc6a9 100644 --- a/packages/dd-trace/src/priority_sampler.js +++ b/packages/dd-trace/src/priority_sampler.js @@ -304,9 +304,13 @@ class PrioritySampler { const rate = sampler.rate() context._trace[SAMPLING_AGENT_DECISION] = rate - context._trace.tags[SAMPLING_KNUTH_RATE] = formatKnuthRate(rate) - context._sampling.mechanism = sampler === defaultSampler ? SAMPLING_MECHANISM_DEFAULT : SAMPLING_MECHANISM_AGENT + if (sampler === defaultSampler) { + context._sampling.mechanism = SAMPLING_MECHANISM_DEFAULT + } else { + context._trace.tags[SAMPLING_KNUTH_RATE] = formatKnuthRate(rate) + context._sampling.mechanism = SAMPLING_MECHANISM_AGENT + } return sampler.isSampled(context) ? AUTO_KEEP : AUTO_REJECT } diff --git a/packages/dd-trace/test/priority_sampler.spec.js b/packages/dd-trace/test/priority_sampler.spec.js index effdcc4e7d..39bbf2f153 100644 --- a/packages/dd-trace/test/priority_sampler.spec.js +++ b/packages/dd-trace/test/priority_sampler.spec.js @@ -370,13 +370,13 @@ describe('PrioritySampler', () => { assert.strictEqual(context._trace['_dd.limit_psr'], 1) }) - it('should set _dd.p.ksr tag for agent sampling', () => { + it('should not set _dd.p.ksr tag for default sampling mechanism', () => { prioritySampler.sample(span) - assert.strictEqual(context._trace.tags[SAMPLING_KNUTH_RATE], '1') + assert.strictEqual(context._trace.tags[SAMPLING_KNUTH_RATE], undefined) }) - it('should set _dd.p.ksr tag for agent sampling with custom rate', () => { + it('should set _dd.p.ksr tag for agent sampling with explicit rates', () => { prioritySampler.update({ 'service:test,env:test': 0.5, }) @@ -413,6 +413,9 @@ describe('PrioritySampler', () => { }) it('should set _dd.p.ksr tag as a string type', () => { + prioritySampler.update({ + 'service:test,env:test': 0.5, + }) prioritySampler.sample(span) assert.strictEqual(typeof context._trace.tags[SAMPLING_KNUTH_RATE], 'string')