Tag consumer spans with the pathway hash on every data streams checkpoint#11808
Conversation
…oint The pathway.hash span tag was only set on the produce/inject path (DataStreamsPropagator.inject). Consumers that checkpoint without injecting (e.g. RabbitMQ) had no pathway.hash, unlike the JS and Python tracers which tag the span on every checkpoint. Set it centrally in DefaultDataStreamsMonitoring.setCheckpoint so all consume-side integrations get it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per review on #11808; the rationale lives in the PR description. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the Java Data Streams Monitoring (DSM) core checkpointing path so spans are tagged with pathway.hash on every DSM checkpoint that has an associated span (including consumer-side checkpoints), aligning behavior with other tracers and improving pathway/span correlation.
Changes:
- Tag spans with
pathway.hashinsideDefaultDataStreamsMonitoring.setCheckpoint(span, context)when a non-zero pathway hash is available. - Add unit tests to validate tagging behavior (non-zero hash, zero hash, and missing pathway context).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java | Tags spans with pathway.hash after PathwayContext.setCheckpoint(...) when hash is non-zero. |
| dd-trace-core/src/test/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoringTest.java | Adds unit tests covering new span-tagging behavior for setCheckpoint. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- cache pathwayContext.getHash() in a local instead of calling it twice - use a negative hash in the test so it actually exercises Long.toUnsignedString Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…bled Now that DefaultDataStreamsMonitoring.setCheckpoint tags the span on every checkpoint, the inferred-proxy (API Gateway) HTTP server span gets a pathway.hash like any other DSM-enabled server span. The shared HttpServerTest already asserts this conditionally; SpringBootBasedTest's hand-rolled inferred-proxy assertions were missing it. Mirror the same guard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
🎯 Code Coverage (details) 🔗 Commit SHA: 945d3d8 | Docs | Datadog PR Page | Give us feedback! |
🟢 Java Benchmark SLOs — All performance SLOs passed
PR vs. master results
Commit: Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion. |
|
/merge |
|
View all feedbacks in Devflow UI.
The expected merge time in
|
What
Set the
pathway.hashspan tag insideDefaultDataStreamsMonitoring.setCheckpoint(span, context)so it is applied on every checkpoint that has a span — consume side included — not only on produce/inject.Why
Today
pathway.hashis written in exactly one place:DataStreamsPropagator.inject(...), which only runs on the produce/inject path. Consumers that checkpoint without injecting downstream context — e.g. RabbitMQ'sbasicGet/basicConsume, which callgetDataStreamsMonitoring().setCheckpoint(span, ...)— compute and emit the pathway hash but never tag their span with it. So consumer spans are missingpathway.hashand can't be correlated back to the pathway.Some consumers (e.g. SQS) happen to get the tag only because their integration also calls
dsmPropagator.inject(...)during receive — an integration-specific side effect, not a guarantee.The JS (
processor.js→recordCheckpoint) and Python (processor.py→set_checkpoint) tracers already set the tag in their central checkpoint method, so it lands on both produce and consume. This change brings Java to parity by doing the same in the coresetCheckpoint.Change
After
pathwayContext.setCheckpoint(...), tag the span withpathway.hashwhen the hash is non-zero. The produce path is unchanged (the propagator still tags on inject; the value is identical, so this is idempotent for producers that also flow throughsetCheckpoint).Tests
Added three unit tests in
DefaultDataStreamsMonitoringTest:./gradlew :dd-trace-core:test --tests "datadog.trace.core.datastreams.DefaultDataStreamsMonitoringTest"→ 36 tests, 0 failures.Context
Found while working on RabbitMQ DSM (the consumer span had no
pathway.hashwhile the producer did). Independent of, and complementary to, the RabbitMQ default-exchange topic fix (#11805).