Skip to content

revert(traces): revert Datadog-Client-Computed-Stats header support#1176

Merged
duncanista merged 2 commits into
mainfrom
revert-client-computed-stats
Apr 9, 2026
Merged

revert(traces): revert Datadog-Client-Computed-Stats header support#1176
duncanista merged 2 commits into
mainfrom
revert-client-computed-stats

Conversation

@duncanista

@duncanista duncanista commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Restores the pre-v95 behavior where _dd.compute_stats is set solely by DD_COMPUTE_TRACE_STATS_ON_EXTENSION, keeping the backend as a safety net.

Test plan

  • cargo fmt --check passes
  • cargo clippy --all-targets -- -D warnings passes
  • cargo test — all 513 tests pass

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reverts changes from PR #1118 and #1136 that introduced logic to respect the Datadog-Client-Computed-Stats header from tracers. The revert restores the pre-v95 behavior where _dd.compute_stats tag is set solely based on the DD_COMPUTE_TRACE_STATS_ON_EXTENSION environment variable, simplifying the stats computation decision and keeping the backend as a safety net.

Changes:

  • Removes client_computed_stats field from the Context struct in invocation context
  • Removes client_computed_stats parameter from trace processing functions and command handlers
  • Moves _dd.compute_stats tag setting back to tags_from_env() function, setting it inversely to compute_trace_stats_on_extension config
  • Removes test functions that verified the conditional _dd.compute_stats behavior based on tracer header
  • Updates logs integration test to expect _dd.compute_stats:1 in output (since default config has extension stats disabled)
  • Updates test count assertions to reflect the addition of _dd.compute_stats tag to function tags map

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
bottlecap/src/traces/trace_processor.rs Removes conditional logic for setting _dd.compute_stats based on client_computed_stats, removes test functions for compute stats behavior, updates test assertions
bottlecap/src/traces/trace_agent.rs Simplifies code by removing type annotation and removing client_computed_stats parameter from add_tracer_span() call
bottlecap/src/tags/lambda/tags.rs Moves _dd.compute_stats logic to tags_from_env(), sets it based solely on compute_trace_stats_on_extension, changes COMPUTE_STATS_KEY from pub(crate) to const, updates test count assertions
bottlecap/src/lifecycle/invocation/processor.rs Removes client_computed_stats parameter from function signatures, removes related test function
bottlecap/src/lifecycle/invocation/processor_service.rs Removes client_computed_stats field from ProcessorCommand::AddTracerSpan enum variant and updates handler
bottlecap/src/lifecycle/invocation/context.rs Removes client_computed_stats field from Context struct and all related usages
bottlecap/tests/logs_integration_test.rs Adds back assertion for _dd.compute_stats:1 in log body

@duncanista
duncanista merged commit 56d4b5b into main Apr 9, 2026
57 checks passed
@duncanista
duncanista deleted the revert-client-computed-stats branch April 9, 2026 01:39
zarirhamza pushed a commit that referenced this pull request Apr 9, 2026
…1176)

- Reverts #1118 (`feat(traces): [SVLS-8734] respect
Datadog-Client-Computed-Stats header`) which introduced logic to skip
backend stats when the tracer claims client-computed-stats, causing
stats to vanish entirely in some scenarios.
- Reverts #1136 (`fix(tests): remove stale _dd.compute_stats:1 assertion
from logs integration test`) which was a follow-up test adjustment for

Restores the pre-v95 behavior where `_dd.compute_stats` is set solely by
`DD_COMPUTE_TRACE_STATS_ON_EXTENSION`, keeping the backend as a safety
net.

- [x] `cargo fmt --check` passes
- [x] `cargo clippy --all-targets -- -D warnings` passes
- [x] `cargo test` — all 513 tests pass

[SVLS-8734]:
https://datadoghq.atlassian.net/browse/SVLS-8734?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
lucaspimentel added a commit that referenced this pull request Jun 11, 2026
## Overview

Makes the extension respect the tracer's `Datadog-Client-Computed-Stats`
header and moves `_dd.compute_stats` from a baked-in function tag to a
per-span backend directive.

We tried supporting the `Datadog-Client-Computed-Stats` header before in
#1118, but that was reverted in #1176.

### Background

Span attribute `_dd.compute_stats` asks the backend to compute trace
stats. It must be set to `"1"` only when nobody else computed them —
neither the extension (agent) nor the tracer. Previously the extension:

1. **Baked `_dd.compute_stats` into the function tags** unconditionally
(`tags_from_env`), which also leaked the key into `_dd.tags.function`.
2. **Ignored `Datadog-Client-Computed-Stats`** entirely, so when a
tracer computed stats client-side, the backend was still asked to
compute them.

### Canonical semantics (validated against the Go agent)

The Go agent (`pkg/serverless/tags/tags.go`) only ever sets
`_dd.compute_stats = "1"`, never `"0"`, and leaves the key absent
otherwise. This PR matches that:

> Set `_dd.compute_stats="1"` iff `!compute_trace_stats_on_extension &&
!client_computed_stats`; otherwise leave it absent.

| `client_computed_stats` (header from tracer) | `compute_on_extension`
(extension config) | who computes | stamp `_dd.compute_stats="1"`?
| -------------------- | --------------------- | --------------- | ---
| true                 | (ignored)             | tracer          | ❌ no
| false                | true                  | extension       | ❌ no
| false                | false                 | backend         | ✅ yes

### Changes

- **`tags/lambda/tags.rs`** — stop baking `_dd.compute_stats` in
`tags_from_env` (no longer leaks into `_dd.tags.function`);
`COMPUTE_STATS_KEY` is now `pub` so the integration test can reuse it
instead of re-declaring the literal.
- **Path A: `traces/trace_processor.rs`** — `ChunkProcessor` gains
`client_computed_stats` and stamps `_dd.compute_stats="1"` per-span only
when neither side computes stats; the extension-side stats-generation
guard in `send_processed_traces` now also skips when
`client_computed_stats` is set.
- **Path B (extension-generated `aws.lambda` span)** —
`client_computed_stats` is propagated from the tracer's placeholder span
through `context.rs` → `processor.rs` → `processor_service.rs` →
`trace_agent.rs`, so Path B reuses the same `ChunkProcessor` stamping
(single source of truth).
- **OTLP: `otlp/agent.rs`** — the OTLP stats-generation guard previously
checked only `compute_trace_stats_on_extension`, so an OTLP request
carrying `Datadog-Client-Computed-Stats` would still generate
extension-side stats and double-count against the tracer. It now also
skips when `client_computed_stats` is set, mirroring the
`send_processed_traces` guard.
- **Single source of truth: `traces/trace_processor.rs`** — the three
decisions over the same two inputs (the per-span `_dd.compute_stats`
stamp, plus the extension-side stats-generation guards in
`send_processed_traces` and `otlp/agent.rs`) are now derived from one
`StatsComputedBy::resolve(compute_on_extension, client_computed_stats)`
helper, so the stamp and the guards can't silently drift apart.

### Note on the header value (cross-runtime)

`Datadog-Client-Computed-Stats` is not standardized (`"true"`
.NET/Java/PHP/Python, `"yes"` JS/Ruby/C++, `"t"` Go). bottlecap consumes
the already-parsed `client_computed_stats` bool from
`libdd_trace_utils`, where any non-empty value → `true`, so the fix
triggers on every runtime. A separate libdatadog PR
([DataDog/libdatadog#2071](DataDog/libdatadog#2071))
aligns the header parsing with the Go agent's `isHeaderTrue`/`ParseBool`
rules; this PR only consumes the bool and does not depend on that
change.

## Testing

- ~**Tier 0** (header-parsing contract)~ — moved to the libdatadog bump
PR #1244, since those tests assert libdatadog parsing behavior that the
`db05e1f → 48da0d8` bump changes. This branch keeps Tiers 1–3 and
rebases onto [#1244](//pull/1244) after
it merges.
- **Tier 1** (`trace_processor.rs`) — truth-table on `Span.meta`,
stats-skip guard via the real `StatsConcentratorService`, and updated
`tags.rs` unit tests asserting the key no longer appears in the tags
map. Fixed the logs/metrics integration tests that asserted the old
leak.
- **Tier 2** (`context.rs`, `processor.rs`) — context-level flag
recording and an end-to-end Path B test driving `send_ctx_spans` through
the `trace_tx` channel, asserting `_dd.compute_stats` on the
`aws.lambda` span across the truth table.
- **Tier 3** (`apm_integration_test.rs`) — full fake-intake E2E routing
a trace through `SendingTraceProcessor::send_processed_traces`: asserts
on the captured `AgentPayload` span meta and on `stats_payloads()`
(stats suppressed unless the extension computes and the tracer did not).

### ⚠️ TODO before merging

- [x] Rebase onto the libdatadog bump PR
([#1244](#1244))
after it merges.
- [ ] E2E tests.

---

> *"Computing stats twice doesn't make them twice as true, it just makes
the backend twice as grumpy."* — Claude 🤖

[APMSVLS-487](https://datadoghq.atlassian.net/browse/APMSVLS-487)

[APMSVLS-487]:
https://datadoghq.atlassian.net/browse/APMSVLS-487?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants