Skip to content

test(debugger): add snapshot correlation tests with Go, .NET and Node.js weblog endpoints - #7425

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 14 commits into
mainfrom
grantseltzer/correlation-tests-go
Oct 23, 2026
Merged

gh-worker-dd-mergequeue-cf854d[bot] merged 14 commits into
mainfrom
grantseltzer/correlation-tests-go

Conversation

@grantseltzer

@grantseltzer grantseltzer commented Jul 30, 2026 •

Copy link
Copy Markdown
Member

Motivation

The RFC: Improving Correlation for Live Debugger Snapshots asks tracers to make one snapshot sampling decision per trace, so a trace emits its whole probe chain or none of it, and to cap each probe at one snapshot per trace. This adds the shared tests for that behavior (feature 564) and the weblog endpoints they need. It enables them for .NET (DataDog/dd-trace-dotnet#9266) and Node.js (DataDog/dd-trace-js#10677, DEBUG-5831).

Note

Taken over from @grantseltzer, with his permission, by @watson. The branch was rebased onto main and the remaining issues fixed. The Node.js enablement, previously stacked on top in #7985, is now part of this PR.

Changes

Tests:

  • Test_Debugger_Coordinated_Sampling sends 30 requests to /debugger/correlation. It asserts that every trace emits either all of the chain's probes or none of them, with at least one full chain.
    • The leaf probe is hit first and makes the trace's decision, and it samples every request.
    • The other probes are limited to one snapshot per second, so independent per-probe sampling emits partial chains.
    • Test_Debugger_Coordinated_Sampling_Line_Probe runs the same test with line probes on the line each method returns on, for tracers without method probes. It's activated through the manifests, like the evaluation timeout guardrail variants.
  • Test_Debugger_Probe_Budgets::test_per_trace_budget probes a loop body and a sibling line via /debugger/correlation/loop/:count. It asserts exactly one snapshot per probe per request, which is one trace.

Weblogs, all documented in end-to-end_weblog.md:

  • Go: endpoints in chi, echo, gin, net-http and net-http-orchestrion, with the Go line mappings.
  • .NET: controller methods.
  • Node.js: endpoints in the Express, TypeScript Express and Fastify weblogs, with identical line numbers in all three.
    • The probed functions return about 0, 400 and 800ms into the request, using real async sleeps.
    • The additions avoid everything the IAST rewriter instruments (+, +=, template literals and some string methods). The debugger scenarios run with IAST enabled, and Dynamic Instrumentation places line probes two lines too early in a file the rewriter rewrites.
    • The new routes move the Node.js CaptureTimeout line from 157 to 159 and Budgets from 163 to 165.
    • The base-image lock and the Node.js entries of the image mirror files are refreshed for the changed fixtures.

Manifests:

  • .NET: enables the method-probe variant from 3.55.0.
  • Node.js: enables the line-probe variant and test_per_trace_budget from >=6.21.0 || ^5.132.0 (a new ref_6_21_0), and marks the method-probe variant as irrelevant.
  • Java: incomplete_test_app. dd-trace-java 1.67.0 implements coordinated sampling and the per-trace cap, but the Java weblog has no correlation endpoints yet.
  • Everything else: missing_feature, or irrelevant for the line-probe variant.

Fixes made while taking this over:

  • Rebased onto main.
  • The using System.Runtime.CompilerServices; added to the .NET DebuggerController.cs moved every line of the file down by one, which broke all existing .NET line-probe tests. The MethodImpl attributes are now fully qualified instead.
  • Includes test(debugger): accept flat dotted dd.trace_id in correlation gate #7572's approved commit, which accepts the flat dd.trace_id key that .NET sends.
  • Documented /debugger/correlation/loop/<count>, which a review comment asked for.
  • Made Test_Debugger_Coordinated_Sampling discriminating. With the same rate on every probe, independent samplers stayed in lockstep and also emitted only whole chains, so the test passed without coordinated sampling.

Testing

The real Node.js express/debugger/index.js routes ran under dd-trace-js with a fake agent and IAST enabled, as in CI, replaying both scenarios with the same probes:

dd-trace-js /debugger/correlation ×30 /debugger/correlation/loop/3
Before DataDog/dd-trace-js#10677 15 full chains, 15 partial body: 3 snapshots, sibling: 1 snapshot
With DataDog/dd-trace-js#10677 30 full chains, 0 partial body: 1 snapshot, sibling: 1 snapshot

With IAST enabled and disabled, a snapshot probe on each mapped Node.js line (20, 159, 165, 178, 184, 188, 194 and 197) pauses on exactly that line.

In CI, all .NET and Node.js end-to-end jobs pass, on both dev and prod. The Node.js jobs run the line-probe variant and test_per_trace_budget.

Checks:

  • ./format.sh --check: mypy, import policy, ruff, yamlfmt, yamllint, the manifest parser and shellcheck pass.
  • The Node.js linter step needs Docker, so I ran ESLint from the Express and Fastify weblog setups directly on their debugger/index.js: both pass.
  • The TypeScript weblog file type-checks with tsc --strict against a minimal Express type stub.

Not addressed here:

  • The newer Go weblogs fiber-v2-orchestrion and net-http-span-pool don't have the correlation endpoints yet. Go's manifest keeps these tests disabled.
  • The RFC's follow-up gaps, runtime_id in the snapshot envelope and an execution-context generation token. An earlier version of this PR tested both. Runtime ID is on hold, and no tracer sends a generation token yet, with no agreed field for it, so the test was removed.

Workflow

  1. ⚠️ Create your PR as draft ⚠️
  2. Work on you PR until the CI passes
  3. Mark it as ready for review
    • Tests, manifest, weblog are modified -> you'll need a review from system-tests-reviewers: ask to one of youre co-worker familiar with the tested feature.
    • Framework is modified, or non obvious usage of it -> get a review from system-tests-core (slack)

🚀 Once your PR is reviewed and the CI green, you can merge it!

🛟 #apm-shared-testing 🛟

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

CODEOWNERS have been resolved as:

tests/debugger/test_debugger_snapshot_correlation.py                    @DataDog/debugger
tests/debugger/utils/probes/probe_snapshot_log_correlation.json         @DataDog/debugger
tests/debugger/utils/probes/probe_snapshot_log_correlation_loop.json    @DataDog/debugger
docs/understand/weblogs/end-to-end_weblog.md                            @DataDog/system-tests-core
manifests/dotnet.yml                                                    @DataDog/system-tests-reviewers
manifests/golang.yml                                                    @DataDog/system-tests-reviewers
manifests/java.yml                                                      @DataDog/system-tests-reviewers
manifests/nodejs.yml                                                    @DataDog/system-tests-reviewers
manifests/php.yml                                                       @DataDog/system-tests-reviewers
manifests/python.yml                                                    @DataDog/system-tests-reviewers
manifests/ruby.yml                                                      @DataDog/system-tests-reviewers
mirror_images.lock.yaml                                                 @DataDog/system-tests-core
mirror_images.yaml                                                      @DataDog/system-tests-core
tests/debugger/test_debugger_probe_budgets.py                           @DataDog/debugger
tests/debugger/utils.py                                                 @DataDog/debugger
utils/_features.py                                                      @DataDog/system-tests-core
utils/build/docker/base-images.lock.json                                @DataDog/system-tests-reviewers
utils/build/docker/dotnet/weblog/Controllers/DebuggerController.cs      @DataDog/system-tests-reviewers
utils/build/docker/golang/app/chi/debugger.go                           @DataDog/system-tests-reviewers
utils/build/docker/golang/app/chi/main.go                               @DataDog/system-tests-reviewers
utils/build/docker/golang/app/echo/debugger.go                          @DataDog/system-tests-reviewers
utils/build/docker/golang/app/echo/main.go                              @DataDog/system-tests-reviewers
utils/build/docker/golang/app/gin/debugger.go                           @DataDog/system-tests-reviewers
utils/build/docker/golang/app/gin/main.go                               @DataDog/system-tests-reviewers
utils/build/docker/golang/app/net-http-orchestrion/debugger.go          @DataDog/system-tests-reviewers
utils/build/docker/golang/app/net-http-orchestrion/main.go              @DataDog/system-tests-reviewers
utils/build/docker/golang/app/net-http/debugger.go                      @DataDog/system-tests-reviewers
utils/build/docker/golang/app/net-http/main.go                          @DataDog/system-tests-reviewers
utils/build/docker/nodejs/express/debugger/index.js                     @DataDog/system-tests-reviewers
utils/build/docker/nodejs/express4-typescript/debugger/index.ts         @DataDog/system-tests-reviewers
utils/build/docker/nodejs/fastify/debugger/index.js                     @DataDog/system-tests-reviewers

@grantseltzer
grantseltzer marked this pull request as ready for review August 3, 2026 13:58
@grantseltzer
grantseltzer requested review from a team as code owners August 3, 2026 13:58
@grantseltzer
grantseltzer requested review from dromanol, florentinl, manuel-alvarez-alvarez and ncybul and removed request for a team August 3, 2026 13:58

@datadog-datadog-prod-us1 datadog-datadog-prod-us1 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Datadog Autotest: PASS

More details

The new correlation chain returns the expected value, and the loop handler safely returns Loop 0 for both zero and negative counts. The shared line-probe mapping targets the newly added loop body and sibling lines consistently across Go weblog variants.

Was this helpful? React 👍 or 👎

📊 Validated against 3 scenarios · Open Bits AI session

🤖 Datadog Autotest · Commit 8431afa · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

@nccatoni nccatoni left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM (from @DataDog/system-tests-core) but you should get a review from someone familiar with the feature

Comment thread tests/debugger/test_debugger_snapshot_correlation.py Outdated
Comment thread tests/debugger/test_debugger_snapshot_correlation.py Outdated
Comment thread tests/debugger/test_debugger_snapshot_correlation.py Outdated
Comment thread tests/debugger/test_debugger_snapshot_correlation.py Outdated
Comment thread tests/debugger/test_debugger_snapshot_correlation.py Outdated
@watson watson changed the title test(debugger): add snapshot-correlation gate and Go weblog endpoints test(debugger): add snapshot correlation tests with Go and .NET weblog endpoints Oct 22, 2026
@watson
watson added this pull request to stack #8146 October 22, 2026 12:31
watson and others added 5 commits October 22, 2026 15:46
Every probe had the same one snapshot per second limit, and each request
hits the probes at the same offsets, so independent per-probe samplers stay
in lockstep and emit whole chains too. The test passed without coordinated
sampling, e.g. for Node.js before coordinated sampling was implemented.

Let the leaf, which is the first probe hit in each request and therefore
decides for the trace, sample every request, and keep the other probes at
one snapshot per second. A request takes about 800ms, so without
coordination those probes are skipped in about every other request and
the chains split. Replaying the scenario against Node.js weblog routes: 15
of 30 chains were partial without coordinated sampling, and all 30 were
complete with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add the `/debugger/correlation` and `/debugger/correlation/loop/:count`
endpoints to the Node.js Express, TypeScript Express and Fastify weblogs,
mirroring the Go endpoints: the probed functions return 400ms apart, and
the loop sleeps for a second per iteration.

The debugger scenarios run the weblogs with IAST enabled, and Dynamic
Instrumentation places line probes two lines too early in files that the
IAST rewriter rewrites. So the endpoints avoid everything the rewriter
instruments (`+`, `+=`, template literals and some string methods) and
respond with constant strings.

Node.js doesn't support method probes, so the correlation tests point each
probe at the line its method returns on for Node.js instead, using new
Node.js entries in the line map. The new routes move the capture timeout
line from 157 to 159, and the budgets line from 163 to 165.

Enable `Test_Debugger_Coordinated_Sampling` and `test_per_span_budget`
from v6.21.0 and v5.132.0, the releases that ship coordinated snapshot
sampling (DataDog/dd-trace-js#10677).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The new debugger fixtures change the content of the express4,
express4-typescript, express5 and fastify base images.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…test

Node.js doesn't support method probes. Instead of branching on the library
in the test, add `Test_Debugger_Coordinated_Sampling_Line_Probe`, which
points each probe at the line its method returns on, using the line map.
Enable it for Node.js, and mark the method-probe variant as irrelevant
there, like the evaluation timeout guardrail test variants. The other
libraries keep the method-probe variant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@watson
watson removed this pull request from stack #8146 October 22, 2026 19:06
@watson watson changed the title test(debugger): add snapshot correlation tests with Go and .NET weblog endpoints test(debugger): add snapshot correlation tests and enable them for .NET and Node.js Oct 22, 2026
@watson
watson requested review from a team October 22, 2026 19:20
@watson watson changed the title test(debugger): add snapshot correlation tests and enable them for .NET and Node.js test(debugger): add snapshot correlation tests with Go, .NET and Node.js weblog endpoints Oct 22, 2026
watson and others added 4 commits October 23, 2026 07:00
Remove Test_Debugger_Snapshot_Correlation_Fields. No tracer sends the
generation token it asserts on, and nothing defines that field yet. Its
thread_id check also fails Java, which sends the key flat, and PHP, which
has no logger object. The runtime ID part is dropped for now.

Rename test_per_span_budget to test_per_trace_budget, since tracers cap each
probe at one snapshot per trace, not per span. Count every collected
snapshot, so tracers that send the flat debugger.snapshot key are counted.

Use a ref for the Node.js 6.21.0 / 5.132.0 versions.

Declare the Java entries incomplete_test_app. dd-trace-java 1.67.0 has
coordinated sampling and the per-trace cap, but the Java weblog has no
/debugger/correlation endpoints.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The RFC says the first snapshot probe hit in a trace decides for the whole
trace, and that once it emits, every probe in the trace may emit until its
cap of one snapshot per trace. The test relies on that: the leaf samples
every request, and the other probes emit past their own one-per-second
rate. Say so in the class docstring.

The leaf is only the first probe hit for line probes on the return lines.
Method probes may count the outer method first, so reword that comment.

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve conflicts with #7995. Keep its Python CaptureTimeout line mapping
next to the moved Node.js line, and its version-scoped DEBUG-5743 entry
next to the new test_per_trace_budget entry in the Python manifest.

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The comment named Ruby as sending both the nested dd object and the flat
dd.trace_id key, and Go as sending the flat key. In CI, Ruby sends only the
flat key and Go sends neither. Describe the two formats without language
lists, which go stale.

Environment: Datadog workspace

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

Copy link
Copy Markdown
Member Author

/merge

@gh-worker-devflow-routing-ef8351

gh-worker-devflow-routing-ef8351 Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

View all feedbacks in Devflow UI.

2026-10-23 14:47:20 UTC ℹ️ Start processing command /merge


2026-10-23 14:47:31 UTC ℹ️ MergeQueue: Pull request is not mergeable yet

It will be processed automatically as soon as GitHub reports it as mergeable. View in MergeQueue UI.

  • Run /code blockers to see what is blocking it.
  • Run /remove to cancel it.

2026-10-23 15:37:32 UTC ℹ️ MergeQueue: merge request added to the queue

The expected merge time in main is approximately 14m (p90).


2026-10-23 15:50:34 UTC ℹ️ MergeQueue: This merge request was merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants