fix(metrics): calculate ddsketch averages from histogram sum & count fields#24379
fix(metrics): calculate ddsketch averages from histogram sum & count fields#24379tony-resendiz wants to merge 16 commits into
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read the CLA Document and I hereby sign the CLA |
0fbff1c to
be24867
Compare
|
hi @fuchsnj sry for the ping. would you mind taking a look at this pr? 🙇 |
| buckets, | ||
| sum, | ||
| count, | ||
| .. |
There was a problem hiding this comment.
I don't see AggregatedHistogram as having any other fields, so the .. seems to be superfluous here.
There was a problem hiding this comment.
thanks for catching, removed it
| let orig_count = *count; | ||
| if orig_count > 0 { | ||
| sketch.sum = orig_sum; | ||
| sketch.count = orig_count as u32; |
There was a problem hiding this comment.
If *count is ever larger than a u32 can hold, I think we would want to leave the sketch.count as it is, and possibly not set sum or avg too. Does that make sense? If so, we'd want to do something along the lines of:
if let Some(count) = *count.try_into() {
sketch.count = count;
}
There was a problem hiding this comment.
yes makes total sense, just pushed an update. it seems like it doesn't require the clippy notes anymore when we do it that way as make check-clippy passes without them now. 👍
Co-authored-by: Bruce Guenter <bruce@untroubled.org>
|
It's also interesting that this didn't affect any existing tests. I wonder if this indicates a testing gap. |
@pront good call i added a test to check the resulting sum, count, average of the sketch. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d93e2596dd
ℹ️ 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".
| sketch.sum = *sum; | ||
| sketch.avg = *sum / f64::from(c); |
There was a problem hiding this comment.
Skip overriding avg when histogram sum may be unknown
Overwriting sketch.sum/sketch.avg from sum / count here can zero out valid histograms when upstream sum is absent. OpenTelemetry histogram sum is optional, and our OTLP conversion currently does sum: self.point.sum.unwrap_or(0.0) (see lib/opentelemetry-proto/src/metrics.rs), so a non-empty histogram with missing sum will now be emitted with avg=0 after this change. Before this commit, the sketch average came from bucket interpolation and remained non-zero for those inputs. Please gate this override on a known sum value (or preserve interpolated stats as fallback).
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 98a1bda6de
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| match u32::try_from(*count) { | ||
| Ok(c) => { | ||
| if c > 0 { | ||
| sketch.count = c; |
There was a problem hiding this comment.
Preserve sketch/bin count consistency when overriding histogram stats
Setting sketch.count directly from histogram count here can break DDSketch invariants for valid inputs where bucket totals differ from count (for example, Prometheus parsing drops the +Inf bucket in src/sources/prometheus/parser.rs lines 133-153 but preserves total count). In that case cnt becomes larger than the total mass represented by n, so later operations that rely on count-vs-bin consistency (e.g. AgentDDSketch::quantile) can return incorrect values/NaN, and encoded sketch payloads carry internally inconsistent statistics.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 371280abaf
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if c > 0 && *sum != 0.0 { | ||
| sketch.count = c; | ||
| sketch.sum = *sum; | ||
| sketch.avg = *sum / f64::from(c); |
There was a problem hiding this comment.
Skip sum/count override when sketch has no interpolated bins
This block overwrites count/sum/avg whenever count > 0 && sum != 0, even if insert_interpolate_buckets inserted nothing. That can happen for valid OTLP histograms that carry only count/sum and no bucket counts (lib/opentelemetry-proto/src/metrics.rs builds buckets: Vec::new() when bucket_counts.len() == 0). In that path, min/max remain at their initialization sentinels and bins stay empty, but the sketch is now treated as non-empty and later encoded, producing corrupted sketch statistics instead of dropping or safely handling the metric.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 90450b23ff
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if c > 0 && *sum != 0.0 && has_buckets { | ||
| sketch.count = c; | ||
| sketch.sum = *sum; | ||
| sketch.avg = *sum / f64::from(c); |
There was a problem hiding this comment.
Require non-empty sketch before overriding summary stats
This branch updates count/sum/avg based only on has_buckets, but has_buckets only checks vector length, not whether any bucket actually contributed samples. If a histogram arrives with bucket entries whose counts are all zero (or otherwise fail to add samples) while count is positive, this code makes the sketch non-empty with count > 0 but leaves min/max at their defaults (f64::MAX/f64::MIN). The Datadog encoder then emits these invalid extrema for a non-empty sketch. Gate this override on actual inserted samples (for example sketch.count() > 0) rather than bucket vector non-emptiness.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 647916b816
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| match u32::try_from(*count) { | ||
| Ok(c) => { | ||
| if c > 0 && *sum != 0.0 && sketch.count() > 0{ | ||
| sketch.count = c; |
There was a problem hiding this comment.
Preserve bin-derived count when overriding histogram average
Do not overwrite sketch.count from the histogram count field here. The interpolated bins already define the sketch's sample mass, and AgentDDSketch::quantile uses self.count to compute rank; if upstream sends a histogram where count and bucket totals differ (this type is accepted without validation), the rank can exceed cumulative bin weights and produce NaN/skewed quantiles. Overriding sum/avg is sufficient for the accuracy fix while keeping count consistent with the bins.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 52d0ee4e15
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| sketch.sum = *sum; | ||
| sketch.avg = *sum / f64::from(c); |
There was a problem hiding this comment.
Guard sum/count override on bucket-count mismatch
This branch overwrites sketch.sum/sketch.avg using histogram-wide sum and count, but sketch.count is still derived only from interpolated buckets. That creates inconsistent sketches when input histograms keep total count/sum larger than represented buckets (for example, Prometheus parsing drops the +Inf bucket in src/sources/prometheus/parser.rs lines 133-138 while preserving count/sum at lines 152-153). In that case we emit cnt from sketch.count but avg/sum from full totals, so downstream receives contradictory stats for the same sketch.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
@codex Good point — this can introduce inconsistencies between sum/avg and the bin-derived count when upstream histogram totals differ from bucket mass (e.g. Prometheus +Inf bucket handling).
In this change, the intent is to improve summary statistic accuracy (avg) while preserving DDSketch invariants for quantile calculations by keeping count aligned with bins.
We accept the potential inconsistency (avg != sum / count) as a tradeoff, since sum/avg are not used in quantile computation and this improves accuracy for common cases.
There was a problem hiding this comment.
To use Codex here, create a Codex account and connect to github.
There was a problem hiding this comment.
To use Codex here, create a Codex account and connect to github.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5cfc57f701
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if c > 0 && *sum != 0.0 && sketch.count() > 0{ | ||
| sketch.sum = *sum; | ||
| sketch.avg = *sum / f64::from(c); |
There was a problem hiding this comment.
Keep sketch avg aligned with retained sketch count
This branch sets avg from the histogram-level count while deliberately not updating sketch.count, which creates an inconsistent sketch whenever those counts differ. That mismatch is real for Prometheus histograms because src/sources/prometheus/parser.rs drops the +Inf bucket (133-138) but still preserves count (152), so avg can be computed against a larger denominator than the sketch actually stores. Once that happens, later aggregation via MetricValue::add -> AgentDDSketch::merge weights averages by self.count, producing incorrect merged averages that are sent in the Datadog sketch payload.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7a840552fa
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| let sc = sketch.count(); | ||
|
|
||
| if c > 0 && *sum != 0.0 && sc > 0 { | ||
| sketch.sum = *sum; | ||
| sketch.avg = *sum / sc as f64; |
There was a problem hiding this comment.
Divide histogram sum by histogram count when overriding avg
When histogram count differs from the interpolated bucket total, this computes avg as sum / sketch.count() rather than sum / histogram.count. In that case (for example when bucket totals are incomplete), the resulting sketch average is still biased by interpolation loss and does not reflect the upstream histogram mean, which defeats the purpose of this fix and can misreport avg downstream.
Useful? React with 👍 / 👎.
|
ok, based on the feedback from chatgpt and codex, it seems like this change would be pretty bad. the ddsketch algorithm is merging histograms/sketches. if we are not preserving the interpolated values (count, avg) in the ddsketch then it can corrupt merging and make matters worse. so the accuracy is a tradeoff for merge-ability. 😮 🤯 |
|
related #25752 |
Summary
when histograms are processed by the datadog metrics sink a ddsketch is built by interpolating values from the bucket boundaries. this causes some slight inaccuracy in the sketch average. this change sets the sketch average to the histogram's sum / count.
Vector configuration
How did you test this PR?
built new vector binary and tested against the above config.
Change Type
Is this a breaking change?
Does this PR include user facing changes?
no-changeloglabel to this PR.References
Notes
@vectordotdev/vectorto reach out to us regarding this PR.pre-pushhook, please see this template.make fmtmake check-clippy(if there are failures it's possible some of them can be fixed withmake clippy-fix)make testgit merge origin masterandgit push.Cargo.lock), pleaserun
make build-licensesto regenerate the license inventory and commit the changes (if any). More details here.