fix(otlp): emit non-overlapping delta metric windows - #10086
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Overall package sizeSelf size: 8.64 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.4.0 | 127.33 kB | 447.04 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f2d04e8281
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| forceFlush (done) { | ||
| this.#flush(done) | ||
| this.#flush(done, true) |
There was a problem hiding this comment.
Prevent force flushes from reopening exported buckets
When a reused Vercel worker handles multiple requests within one wall-clock bucket, flushAll() invokes this force flush after every request, so the first request drains and exports the still-open bucket; a later span then recreates the same timeNs, and the next flush exports another point with the identical [timeNs, timeNs + bucketSizeNs] window. This preserves the overlap that the change is intended to eliminate, so force flushes need to retain a boundary/state that lets subsequent data use a non-overlapping window while still completing lifecycle delivery.
AGENTS.md reference: AGENTS.md:L76-L80
Useful? React with 👍 / 👎.
| #flush (done, force = false) { | ||
| const drained = this.#drainBuckets(this.otlpExporter && !force ? Date.now() * 1e6 : Infinity) |
There was a problem hiding this comment.
Use the span timestamp clock for the bucket cutoff
If the system wall clock is corrected while a span is active, this cutoff and the bucket timestamps can diverge: formatted span end times are anchored to Date.now() at trace creation but advance using performance.now(), whereas this newly added cutoff reads the current Date.now(). A forward correction can therefore drain a bucket before a pre-correction span later lands in it, recreating an already-exported window; a backward correction can retain completed buckets until the wall clock catches up. Derive the cutoff from the same monotonic epoch clock as span timestamps.
AGENTS.md reference: AGENTS.md:L76-L80
Useful? React with 👍 / 👎.
BenchmarksBenchmark execution time: 2026-08-31 19:59:07 Comparing candidate commit f2d04e8 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 2293 metrics, 17 unstable metrics.
|
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: f2d04e8 | Docs | View more details | Give us feedback! |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #10086 +/- ##
=======================================
Coverage 98.62% 98.62%
=======================================
Files 996 996
Lines 152034 152045 +11
Branches 13117 13061 -56
=======================================
+ Hits 149947 149958 +11
Misses 2087 2087 Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
What does this PR do?
Prevents overlapping OTLP delta metric windows in the TraceMetrics and general metrics exporters.
For
traces.span.sdk.metrics.duration, periodic flushes now retain the active wall-clock bucket until it is complete. This keeps spans recorded on both sides of a process-relative timer tick in one histogram point. Explicit force flushes continue to drain all pending buckets.For general delta counters and histograms, each point now ends at collection time and that endpoint becomes the next point start. Counts, sums, and histogram buckets are unchanged.
Motivation
The TraceMetrics timer can fire before its active wall-clock bucket closes. Draining that bucket early allows later spans to recreate the same
(startTimeUnixNano, timeUnixNano]window, producing overlapping delta histogram points that an OTLP receiver cannot safely combine.Testing
./node_modules/.bin/mocha packages/dd-trace/test/span_stats.spec.js packages/dd-trace/test/opentelemetry/metrics.spec.js./node_modules/.bin/eslint packages/dd-trace/src/span_stats.js packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js packages/dd-trace/test/span_stats.spec.js packages/dd-trace/test/opentelemetry/metrics.spec.js --max-warnings 0