diff --git a/promql/quantile.go b/promql/quantile.go index 6e63efab6..a25f8917c 100644 --- a/promql/quantile.go +++ b/promql/quantile.go @@ -168,7 +168,7 @@ func coalesceBuckets(buckets buckets) buckets { func ensureMonotonic(buckets buckets) { max := buckets[0].count - for i := range buckets[1:] { + for i := 1; i < len(buckets); i++ { switch { case buckets[i].count > max: max = buckets[i].count diff --git a/promql/testdata/histograms.test b/promql/testdata/histograms.test index b7ec13682..ec236576b 100644 --- a/promql/testdata/histograms.test +++ b/promql/testdata/histograms.test @@ -151,21 +151,25 @@ eval instant at 50m histogram_quantile(0.5, rate(request_duration_seconds_bucket # A histogram with nonmonotonic bucket counts. This may happen when recording # rule evaluation or federation races scrape ingestion, causing some buckets -# counts to be derived from fewer samples. The wrong answer we want to avoid -# is for histogram_quantile(0.99, nonmonotonic_bucket) to return ~1000 instead -# of 1. +# counts to be derived from fewer samples. load 5m - nonmonotonic_bucket{le="0.1"} 0+1x10 - nonmonotonic_bucket{le="1"} 0+9x10 - nonmonotonic_bucket{le="10"} 0+8x10 - nonmonotonic_bucket{le="100"} 0+8x10 + nonmonotonic_bucket{le="0.1"} 0+2x10 + nonmonotonic_bucket{le="1"} 0+1x10 + nonmonotonic_bucket{le="10"} 0+5x10 + nonmonotonic_bucket{le="100"} 0+4x10 nonmonotonic_bucket{le="1000"} 0+9x10 - nonmonotonic_bucket{le="+Inf"} 0+9x10 + nonmonotonic_bucket{le="+Inf"} 0+8x10 # Nonmonotonic buckets +eval instant at 50m histogram_quantile(0.01, nonmonotonic_bucket) + {} 0.0045 + +eval instant at 50m histogram_quantile(0.5, nonmonotonic_bucket) + {} 8.5 + eval instant at 50m histogram_quantile(0.99, nonmonotonic_bucket) - {} 0.989875 + {} 979.75 # Buckets with different representations of the same upper bound. eval instant at 50m histogram_quantile(0.5, rate(mixed_bucket[5m]))