From 06a8886b94e18c65fe682da1a66c0172f8236494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Krajcsovits?= Date: Mon, 12 Aug 2024 10:39:08 +0200 Subject: [PATCH 1/3] Native histograms: define behavior when rate is null. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Histogram quantile returns NaN in this case, which might be surprising, so add a unit test that clarifies that this is intentional. Signed-off-by: György Krajcsovits --- promql/promqltest/testdata/histograms.test | 29 ++++++++++++++ .../testdata/native_histograms.test | 39 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/promql/promqltest/testdata/histograms.test b/promql/promqltest/testdata/histograms.test index 349a1e79c..ef3ca0078 100644 --- a/promql/promqltest/testdata/histograms.test +++ b/promql/promqltest/testdata/histograms.test @@ -482,3 +482,32 @@ load_with_nhcb 5m eval_fail instant at 50m histogram_quantile(0.99, {__name__=~"request_duration_seconds\\d*_bucket"}) eval_fail instant at 50m histogram_quantile(0.99, {__name__=~"request_duration_seconds\\d*"}) + +# Histogram with constant buckets. +load_with_nhcb 1m + const_histogram_bucket{le="0.0"} 1 1 1 1 1 + const_histogram_bucket{le="1.0"} 1 1 1 1 1 + const_histogram_bucket{le="2.0"} 1 1 1 1 1 + const_histogram_bucket{le="+Inf"} 1 1 1 1 1 + +# There is no change to the bucket count over time, thus rate is 0 in each bucket. +eval instant at 5m rate(const_histogram_bucket[5m]) + {le="0.0"} 0 + {le="1.0"} 0 + {le="2.0"} 0 + {le="+Inf"} 0 + +# There is no change to the bucket count over time, thus rate is 0 in each bucket. +# However native histograms do not represent empty buckets, so here the zeros are implicit. +eval instant at 5m rate(const_histogram[5m]) + {} {{schema:-53 sum:0 count:0 custom_values:[0.0 1.0 2.0]}} + +# Zero buckets mean no observations, so there is no value that observations fall bellow, +# which means that any quantile is a NaN. +eval instant at 5m histogram_quantile(1.0, sum by (le) (rate(const_histogram_bucket[5m]))) + {} NaN + +# Zero buckets mean no observations, so there is no value that observations fall bellow, +# which means that any quantile is a NaN. +eval instant at 5m histogram_quantile(1.0, sum(rate(const_histogram[5m]))) + {} NaN diff --git a/promql/promqltest/testdata/native_histograms.test b/promql/promqltest/testdata/native_histograms.test index f91626c34..a9ac0303c 100644 --- a/promql/promqltest/testdata/native_histograms.test +++ b/promql/promqltest/testdata/native_histograms.test @@ -784,3 +784,42 @@ eval_warn instant at 1m rate(some_metric[30s]) # Start with exponential, end with custom. eval_warn instant at 30s rate(some_metric[30s]) # Should produce no results. + +# Histogram with constant buckets. +load 1m + const_histogram {{schema:0 sum:1 count:1 buckets:[1 1 1]}} {{schema:0 sum:1 count:1 buckets:[1 1 1]}} {{schema:0 sum:1 count:1 buckets:[1 1 1]}} {{schema:0 sum:1 count:1 buckets:[1 1 1]}} {{schema:0 sum:1 count:1 buckets:[1 1 1]}} + +# There is no change to the bucket count over time, thus rate is 0 in each bucket. +# However native histograms do not represent empty buckets, so here the zeros are implicit. +eval instant at 5m rate(const_histogram[5m]) + {} {{schema:0 sum:0 count:0}} + +# Zero buckets mean no observations, so average has no meaningful value. +eval instant at 5m histogram_avg(rate(const_histogram[5m])) + {} NaN + +# Zero buckets mean no observations, so count is 0. +eval instant at 5m histogram_count(rate(const_histogram[5m])) + {} 0.0 + +# Zero buckets mean no observations, so the sum should be NaN, However +# we return 0 for compatibility with classic histograms. +eval instant at 5m histogram_sum(rate(const_histogram[5m])) + {} 0.0 + +# BUG??? Zero buckets mean no observations, thus any fraction should be 0. +eval instant at 5m histogram_fraction(0.0, 1.0, rate(const_histogram[5m])) + {} NaN + +# Zero buckets mean no observations, so there is no value that observations fall bellow, +# which means that any quantile is a NaN. +eval instant at 5m histogram_quantile(1.0, rate(const_histogram[5m])) + {} NaN + +# Zero buckets mean no observations, so there is no standard deviation. +eval instant at 5m histogram_stddev(rate(const_histogram[5m])) + {} NaN + +# Zero buckets mean no observations, so there is no standard variance. +eval instant at 5m histogram_stdvar(rate(const_histogram[5m])) + {} NaN From 6aee5b4b38fb2653dc1a93eda960f24de56f1305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Krajcsovits?= Date: Mon, 12 Aug 2024 12:04:45 +0200 Subject: [PATCH 2/3] fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: György Krajcsovits --- promql/promqltest/testdata/histograms.test | 4 ++-- promql/promqltest/testdata/native_histograms.test | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/promql/promqltest/testdata/histograms.test b/promql/promqltest/testdata/histograms.test index ef3ca0078..70df9434e 100644 --- a/promql/promqltest/testdata/histograms.test +++ b/promql/promqltest/testdata/histograms.test @@ -502,12 +502,12 @@ eval instant at 5m rate(const_histogram_bucket[5m]) eval instant at 5m rate(const_histogram[5m]) {} {{schema:-53 sum:0 count:0 custom_values:[0.0 1.0 2.0]}} -# Zero buckets mean no observations, so there is no value that observations fall bellow, +# Zero buckets mean no observations, so there is no value that observations fall below, # which means that any quantile is a NaN. eval instant at 5m histogram_quantile(1.0, sum by (le) (rate(const_histogram_bucket[5m]))) {} NaN -# Zero buckets mean no observations, so there is no value that observations fall bellow, +# Zero buckets mean no observations, so there is no value that observations fall below, # which means that any quantile is a NaN. eval instant at 5m histogram_quantile(1.0, sum(rate(const_histogram[5m]))) {} NaN diff --git a/promql/promqltest/testdata/native_histograms.test b/promql/promqltest/testdata/native_histograms.test index a9ac0303c..948e15806 100644 --- a/promql/promqltest/testdata/native_histograms.test +++ b/promql/promqltest/testdata/native_histograms.test @@ -811,7 +811,7 @@ eval instant at 5m histogram_sum(rate(const_histogram[5m])) eval instant at 5m histogram_fraction(0.0, 1.0, rate(const_histogram[5m])) {} NaN -# Zero buckets mean no observations, so there is no value that observations fall bellow, +# Zero buckets mean no observations, so there is no value that observations fall below, # which means that any quantile is a NaN. eval instant at 5m histogram_quantile(1.0, rate(const_histogram[5m])) {} NaN From 386fc8b9f69c0ac5ca81273a145ced408ea9d6d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Krajcsovits?= Date: Tue, 13 Aug 2024 15:26:07 +0200 Subject: [PATCH 3/3] Update from review comments. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: György Krajcsovits --- promql/promqltest/testdata/histograms.test | 5 +---- promql/promqltest/testdata/native_histograms.test | 13 +++++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/promql/promqltest/testdata/histograms.test b/promql/promqltest/testdata/histograms.test index 70df9434e..47cba7993 100644 --- a/promql/promqltest/testdata/histograms.test +++ b/promql/promqltest/testdata/histograms.test @@ -497,8 +497,7 @@ eval instant at 5m rate(const_histogram_bucket[5m]) {le="2.0"} 0 {le="+Inf"} 0 -# There is no change to the bucket count over time, thus rate is 0 in each bucket. -# However native histograms do not represent empty buckets, so here the zeros are implicit. +# Native histograms do not represent empty buckets, so here the zeros are implicit. eval instant at 5m rate(const_histogram[5m]) {} {{schema:-53 sum:0 count:0 custom_values:[0.0 1.0 2.0]}} @@ -507,7 +506,5 @@ eval instant at 5m rate(const_histogram[5m]) eval instant at 5m histogram_quantile(1.0, sum by (le) (rate(const_histogram_bucket[5m]))) {} NaN -# Zero buckets mean no observations, so there is no value that observations fall below, -# which means that any quantile is a NaN. eval instant at 5m histogram_quantile(1.0, sum(rate(const_histogram[5m]))) {} NaN diff --git a/promql/promqltest/testdata/native_histograms.test b/promql/promqltest/testdata/native_histograms.test index 948e15806..c2a5012e9 100644 --- a/promql/promqltest/testdata/native_histograms.test +++ b/promql/promqltest/testdata/native_histograms.test @@ -794,7 +794,8 @@ load 1m eval instant at 5m rate(const_histogram[5m]) {} {{schema:0 sum:0 count:0}} -# Zero buckets mean no observations, so average has no meaningful value. +# Zero buckets mean no observations, thus the denominator in the average is 0 +# leading to 0/0, which is NaN. eval instant at 5m histogram_avg(rate(const_histogram[5m])) {} NaN @@ -802,15 +803,19 @@ eval instant at 5m histogram_avg(rate(const_histogram[5m])) eval instant at 5m histogram_count(rate(const_histogram[5m])) {} 0.0 -# Zero buckets mean no observations, so the sum should be NaN, However -# we return 0 for compatibility with classic histograms. +# Zero buckets mean no observations and empty histogram has a sum of 0 by definition. eval instant at 5m histogram_sum(rate(const_histogram[5m])) {} 0.0 -# BUG??? Zero buckets mean no observations, thus any fraction should be 0. +# Zero buckets mean no observations, thus the denominator in the fraction is 0, +# leading to 0/0, which is NaN. eval instant at 5m histogram_fraction(0.0, 1.0, rate(const_histogram[5m])) {} NaN +# Workaround to calculate the observation count corresponding to NaN fraction. +eval instant at 5m histogram_count(rate(const_histogram[5m])) == 0.0 or histogram_fraction(0.0, 1.0, rate(const_histogram[5m])) * histogram_count(rate(const_histogram[5m])) + {} 0.0 + # Zero buckets mean no observations, so there is no value that observations fall below, # which means that any quantile is a NaN. eval instant at 5m histogram_quantile(1.0, rate(const_histogram[5m]))