Add _dd.p.ksr propagated tag for Knuth sampling rate by bm1549 · Pull Request #10802 · DataDog/dd-trace-java

@bm1549 @claude

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

This was referenced

Mar 11, 2026

and others added 2 commits

March 10, 2026 22:32
- Remove unused imports in KnuthSamplingRateTest (CodeNarc violations)
- Update OT31ApiTest and OT33ApiTest to expect _dd.p.ksr in
  x-datadog-tags when agent-rate sampler runs (UNSET priority)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The _dd.p.ksr propagated tag also appears in W3C tracestate as t.ksr.
Update OT31 and OT33 test expectations for the UNSET context priority
case where the agent-rate sampler runs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace String#replaceAll (a forbidden API in this codebase) with
manual character-based trailing-zero stripping logic that has the
same semantics but avoids the regex-based method.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The PTagsCodec headerValue method outputs tags in order: dm, tid, ksr.
The test datadogTags list had ksr before tid, causing a comparison
failure. Reorder to match the actual output: dm, tid, ksr.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ksr implementation now adds _dd.p.ksr tag to spans with agent
sampling rate, so the msgpack serialization test expectations need
to include it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- OpenTelemetryTest: fix x-datadog-tags ordering (tid before ksr)
- DatadogPropagatorTest: add ksr to expected tags when UNSET priority
- OpenTracing32Test: add ksr and tid handling for UNSET priority case

All follow PTagsCodec ordering: dm → tid → ksr

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update the test inject extract expectations to include _dd.p.ksr=1 in
x-datadog-tags and t.ksr:1 in tracestate for the UNSET sampling case,
following PTagsCodec ordering: dm -> tid -> ksr.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@bm1549 bm1549 marked this pull request as ready for review

March 17, 2026 01:23

bm1549 added a commit to DataDog/dd-trace-rs that referenced this pull request

Mar 19, 2026
# What does this PR do?

Adds `_dd.p.ksr` (Knuth Sampling Rate) as a propagated tag set when
agent-based or rule-based sampling decisions are made. The tag is stored
in span `meta` (string type) with up to 6 significant digits and no
trailing zeros.

`format_sampling_rate` now returns `Option<String>` and guards against
invalid inputs (negative, >1.0, NaN, infinity), returning `None` instead
of producing garbage output.

# Motivation

To enable consistent sampling across tracers and backend retention
filters, the backend needs to know the sampling rate applied by the
tracer. Without transmitting the tracer's rate via `_dd.p.ksr`, backend
resampling cannot correctly compute effective rates in multi-stage
sampling scenarios.

See RFC: "Transmit Knuth sampling rate to backend"

# Additional Notes

Key files changed:
- `datadog-opentelemetry/src/core/constants.rs` — Added
`SAMPLING_KNUTH_RATE_TAG_KEY` constant
- `datadog-opentelemetry/src/sampling/datadog_sampler.rs` — Added
`format_sampling_rate()` helper (returns `Option<String>`, defensive
against invalid rates) and set ksr in agent/rule sampling paths
- Updated 2 snapshot JSON files

Related PRs across tracers:
- Java: DataDog/dd-trace-java#10802
- .NET: DataDog/dd-trace-dotnet#8287
- Ruby: DataDog/dd-trace-rb#5436
- Node.js: DataDog/dd-trace-js#7741
- PHP: DataDog/dd-trace-php#3701
- C++: DataDog/dd-trace-cpp#288
- System tests: DataDog/system-tests#6466

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

dougqh

dougqh

@bm1549 @claude

…r as primitive double

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

dougqh

bm1549 added a commit to DataDog/dd-trace-go that referenced this pull request

Mar 19, 2026
### What does this PR do?

Fixes `_dd.p.ksr` (Knuth Sampling Rate) to only be set on spans when the
agent has provided sampling rates via `readRatesJSON()`. Previously, ksr
was unconditionally set in `prioritySampler.apply()`, including when the
rate was the initial client-side default (1.0) before any agent response
arrived.

Also refactors `prioritySampler` to consolidate lock acquisitions:
extracts `getRateLocked()` so `apply()` acquires `ps.mu.RLock` only once
to read both the rate and `agentRatesLoaded`.

### Motivation

Cross-language consistency: Python, Java, PHP, and other tracers only
set ksr when actual agent rates or sampling rules are applied, not for
the default fallback. This aligns Go with that behavior.

See RFC: "Transmit Knuth sampling rate to backend"

### Additional Notes

- Added `agentRatesLoaded` bool field to `prioritySampler`, set to
`true` in `readRatesJSON()`
- `apply()` now gates ksr behind `agentRatesLoaded` check
- Extracted `getRateLocked()` to avoid double lock acquisition in
`apply()`
- Rule-based sampling path (`applyTraceRuleSampling` in span.go)
unchanged — correctly always sets ksr
- Tests added: `ksr-not-set-without-agent-rates` and
`ksr-set-after-agent-rates-received`

Related PRs across tracers:
- Java: DataDog/dd-trace-java#10802
- .NET: DataDog/dd-trace-dotnet#8287
- Ruby: DataDog/dd-trace-rb#5436
- Node.js: DataDog/dd-trace-js#7741
- PHP: DataDog/dd-trace-php#3701
- Rust: DataDog/dd-trace-rs#180
- C++: DataDog/dd-trace-cpp#288
- System tests: DataDog/system-tests#6466

### Reviewer's Checklist

- [x] Changed code has unit tests for its functionality at or near 100%
coverage.
- [x] [System-Tests](https://github.com/DataDog/system-tests/) covering
this feature have been added and enabled with the va.b.c-dev version
tag.
- [ ] There is a benchmark for any new code, or changes to existing
code.
- [x] If this interacts with the agent in a new way, a system test has
been added.
- [x] New code is free of linting errors. You can check this by running
`make lint` locally.
- [x] New code doesn't break existing tests. You can check this by
running `make test` locally.
- [ ] Add an appropriate team label so this PR gets put in the right
place for the release notes.
- [ ] All generated files are up to date. You can check this by running
`make generate` locally.
- [ ] Non-trivial go.mod changes, e.g. adding new modules, are reviewed
by @DataDog/dd-trace-go-guild. Make sure all nested modules are up to
date by running `make fix-modules` locally.

Unsure? Have a question? Request a review!

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Dario Castañé <dario.castane@datadoghq.com>
Co-authored-by: Mikayla Toffler <46911781+mtoffl01@users.noreply.github.com>
…ay arithmetic

Replace String.format(Locale.ROOT, "%.6g", rate) with manual char-array
formatting that avoids Formatter/stream/boxing allocations. Benchmarks
show ~30x improvement (320ns -> 11ns).

Additionally, cache the TagValue in updateKnuthSamplingRate() so that
getKnuthSamplingRateTagValue() is a simple volatile read (~1.2ns) instead
of re-formatting and re-looking up the TagValue on every header injection.

Add JMH benchmark (KnuthSamplingRateFormatBenchmark) comparing all three
approaches and expand test coverage to all magnitude buckets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement scientific notation (rates < 1e-4) with manual char-array
formatting, removing the last String.format dependency. The method
now uses zero Formatter/Locale allocations for all rate values.

Add test coverage for scientific notation: 1e-05, 5e-05, 1.23457e-05,
1e-07, 5.5e-10.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

dougqh

@bm1549 @claude

Two changes:

1. Benchmark (address dougqh feedback):
   - Switch to Throughput mode + @threads(8) to surface GC pressure
   - @State(Scope.Thread): each thread gets its own PTags, models real traces
   - Add updateRateFreshTrace: resets instance cache each iteration to model
     per-trace cost (the actual hot path Doug was concerned about)
   - Update run instructions to include -t 8 -prof gc

2. Static cache for KSR TagValue (Option A):
   - Add static volatile cachedKsrRate + cachedKsrTagValue to PTags
   - On updateKnuthSamplingRate, check static cache before formatting
   - Eliminates char[]+String allocation on the per-trace path in steady state
     (every new PTags starts with NaN; without the cache, each trace root
     re-formats even when the rate is constant)
   - Race is benign: two threads computing the same rate produce equal TagValues
   - gc.alloc.rate.norm: updateRateFreshTrace goes from 80 B/op → ≈ 0 B/op
     structurally (not JIT-dependent)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

bm1549 added a commit that referenced this pull request

Mar 21, 2026
The tibco-testing pipeline has hardcoded expected span meta maps that
break whenever new propagation tags are added (e.g. _dd.p.ksr from
#10802). Remove the trigger to unblock master.

See also: #10906

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

bm1549 added a commit to DataDog/dd-trace-dotnet that referenced this pull request

Mar 25, 2026
## Summary of changes

Add `_dd.p.ksr` (Knuth Sampling Rate) propagated tag to spans when
sampling is applied via agent rates or trace sampling rules, per the
[Transmit Knuth Sampling Rate to Backend
RFC](https://docs.google.com/document/d/1Po3qtJb6PGheFeKFSUMv2pVY_y-HFAxTzNLuacCbCXY/edit).

## Reason for change

The backend needs to know the exact sampling rate applied by the tracer
to correctly compute effective rates during resampling (e.g., tracer 0.5
× backend 0.5 = effective 0.25). This tag enables that by propagating
the rate via `x-datadog-tags` and W3C `tracestate`.

## Implementation details

- Set `_dd.p.ksr` in `TraceContext.SetSamplingPriority()` for
`AgentRate`, `LocalTraceSamplingRule`, `RemoteAdaptiveSamplingRule`, and
`RemoteUserSamplingRule` mechanisms
- Use `TryAddTag` to preserve the original rate (consistent with
`AppliedSamplingRate ??= rate` semantics)
- Format with `"0.######"` (up to 6 decimal digits, no trailing zeros,
no scientific notation) per RFC spec
- Added `.IsOptional("_dd.p.ksr")` to `SpanTagAssertion.cs` so
integration test tag validators accept the new tag

## Test coverage

- Unit tests in `TraceContextTests_KnuthSamplingRate.cs`:
  - KSR set for agent rate sampling
- KSR set for trace sampling rules (local, remote adaptive, remote user)
- KSR NOT set for manual, AppSec, rate limiter, or single span
mechanisms
  - KSR preserved on subsequent sampling calls (TryAddTag semantics)
- Formatting with up to 6 decimal digits (boundary values including
small rates like 0.00001)
- System tests in [system-tests
#6466](DataDog/system-tests#6466)

## Other details

Related PRs across tracers:
- Java: DataDog/dd-trace-java#10802
- Ruby: DataDog/dd-trace-rb#5436
- Node.js: DataDog/dd-trace-js#7741
- PHP: DataDog/dd-trace-php#3701
- Rust: DataDog/dd-trace-rs#180
- C++: DataDog/dd-trace-cpp#288

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>