remove eval_with_nhcb

Signed-off-by: Jeanette Tan <jeanette.tan@grafana.com>
This commit is contained in:
Jeanette Tan 2024-06-20 22:49:00 +08:00
parent a6d788b1be
commit fc9dc72028
3 changed files with 46 additions and 109 deletions

View file

@ -130,14 +130,3 @@ eval_fail instant at 1m ceil({__name__=~'testmetric1|testmetric2'})
eval_fail instant at 1m ceil({__name__=~'testmetric1|testmetric2'}) eval_fail instant at 1m ceil({__name__=~'testmetric1|testmetric2'})
expected_fail_regexp (vector cannot contain metrics .*|something else went wrong) expected_fail_regexp (vector cannot contain metrics .*|something else went wrong)
``` ```
### Native histograms with custom buckets (NHCB)
For native histogram with custom buckets (NHCB) series that have been loaded with `load_with_nhcb`, you can use `eval_with_nhcb` instead on the queries of the classic histogram float bucket series to run additional queries on the
NHCB version. We use best effort heuristics to convert the query to its NHCB equivalent, and raise an error if it looks like the conversion was not effective.
For example, `eval_with_nhcb instant at 50m histogram_quantile(0.3, sum(rate(request_duration_seconds_bucket[5m])) by (le, job))` is shorthand for running these queries:
```
eval instant at 50m histogram_quantile(0.3, sum(rate(request_duration_seconds_bucket[5m])) by (le, job)) # Classic histogram
eval instant at 50m histogram_quantile(0.3, sum(rate(request_duration_seconds[5m])) by (job)) # NHCB
```

View file

@ -44,38 +44,10 @@ import (
) )
var ( var (
patSpace = regexp.MustCompile("[\t ]+") patSpace = regexp.MustCompile("[\t ]+")
patLoad = regexp.MustCompile(`^load(?:_(with_nhcb))?\s+(.+?)$`) patLoad = regexp.MustCompile(`^load(?:_(with_nhcb))?\s+(.+?)$`)
patEvalInstant = regexp.MustCompile(`^eval(?:_(with_nhcb))?(?:_(fail|warn|ordered))?\s+instant\s+(?:at\s+(.+?))?\s+(.+)$`) patEvalInstant = regexp.MustCompile(`^eval(?:_(fail|warn|ordered))?\s+instant\s+(?:at\s+(.+?))?\s+(.+)$`)
patEvalRange = regexp.MustCompile(`^eval(?:_(fail|warn))?\s+range\s+from\s+(.+)\s+to\s+(.+)\s+step\s+(.+?)\s+(.+)$`) patEvalRange = regexp.MustCompile(`^eval(?:_(fail|warn))?\s+range\s+from\s+(.+)\s+to\s+(.+)\s+step\s+(.+?)\s+(.+)$`)
patWhitespace = regexp.MustCompile(`\s+`)
patBucket = regexp.MustCompile(`_bucket\b`)
patLE = regexp.MustCompile(`\ble\b`)
histogramBucketReplacements = []struct {
pattern *regexp.Regexp
repl string
}{
{
pattern: regexp.MustCompile(`_bucket\b`),
repl: "",
},
{
pattern: regexp.MustCompile(`\s+by\s+\(\s*le\s*\)`),
repl: "",
},
{
pattern: regexp.MustCompile(`\(\s*le\s*,\s*`),
repl: "(",
},
{
pattern: regexp.MustCompile(`,\s*le\s*,\s*`),
repl: ", ",
},
{
pattern: regexp.MustCompile(`,\s*le\s*\)`),
repl: ")",
},
}
) )
const ( const (
@ -251,19 +223,17 @@ func (t *test) parseEval(lines []string, i int) (int, *evalCmd, error) {
rangeParts := patEvalRange.FindStringSubmatch(lines[i]) rangeParts := patEvalRange.FindStringSubmatch(lines[i])
if instantParts == nil && rangeParts == nil { if instantParts == nil && rangeParts == nil {
return i, nil, raise(i, "invalid evaluation command. Must be either 'eval[_with_nhcb][_fail|_warn|_ordered] instant [at <offset:duration>] <query>' or 'eval[_fail|_warn] range from <from> to <to> step <step> <query>'") return i, nil, raise(i, "invalid evaluation command. Must be either 'eval[_fail|_warn|_ordered] instant [at <offset:duration>] <query>' or 'eval[_fail|_warn] range from <from> to <to> step <step> <query>'")
} }
isInstant := instantParts != nil isInstant := instantParts != nil
var withNHCB bool
var mod string var mod string
var expr string var expr string
if isInstant { if isInstant {
withNHCB = instantParts[1] == "with_nhcb" mod = instantParts[1]
mod = instantParts[2] expr = instantParts[3]
expr = instantParts[4]
} else { } else {
mod = rangeParts[1] mod = rangeParts[1]
expr = rangeParts[5] expr = rangeParts[5]
@ -291,7 +261,7 @@ func (t *test) parseEval(lines []string, i int) (int, *evalCmd, error) {
var cmd *evalCmd var cmd *evalCmd
if isInstant { if isInstant {
at := instantParts[3] at := instantParts[2]
offset, err := model.ParseDuration(at) offset, err := model.ParseDuration(at)
if err != nil { if err != nil {
return i, nil, formatErr("invalid timestamp definition %q: %s", at, err) return i, nil, formatErr("invalid timestamp definition %q: %s", at, err)
@ -335,7 +305,6 @@ func (t *test) parseEval(lines []string, i int) (int, *evalCmd, error) {
case "warn": case "warn":
cmd.warn = true cmd.warn = true
} }
cmd.withNHCB = withNHCB
for j := 1; i+1 < len(lines); j++ { for j := 1; i+1 < len(lines); j++ {
i++ i++
@ -673,7 +642,6 @@ type evalCmd struct {
isRange bool // if false, instant query isRange bool // if false, instant query
fail, warn, ordered bool fail, warn, ordered bool
withNHCB bool
expectedFailMessage string expectedFailMessage string
expectedFailRegexp *regexp.Regexp expectedFailRegexp *regexp.Regexp
@ -1066,26 +1034,6 @@ func (t *test) execInstantEval(cmd *evalCmd, engine promql.QueryEngine) error {
if err := t.runInstantQuery(iq, cmd, engine); err != nil { if err := t.runInstantQuery(iq, cmd, engine); err != nil {
return err return err
} }
if cmd.withNHCB {
if !strings.Contains(iq.expr, "_bucket") {
return fmt.Errorf("expected '_bucket' in the expression '%q'", iq.expr)
}
origExpr := iq.expr
for _, rep := range histogramBucketReplacements {
iq.expr = rep.pattern.ReplaceAllString(iq.expr, rep.repl)
}
switch {
case patWhitespace.ReplaceAllString(iq.expr, "") == patWhitespace.ReplaceAllString(origExpr, ""):
return fmt.Errorf("query rewrite of '%q' had no effect", iq.expr)
case patBucket.MatchString(iq.expr):
return fmt.Errorf("rewritten query '%q' still has '_bucket'", iq.expr)
case patLE.MatchString(iq.expr):
return fmt.Errorf("rewritten query '%q' still has 'le'", iq.expr)
}
if err := t.runInstantQuery(iq, cmd, engine); err != nil {
return err
}
}
} }
return nil return nil
} }

View file

@ -105,149 +105,149 @@ eval instant at 50m histogram_fraction(0, 0.2, rate(testhistogram3[5m]))
# Test histogram_quantile. # Test histogram_quantile.
eval_with_nhcb instant at 50m histogram_quantile(0, testhistogram3_bucket) eval instant at 50m histogram_quantile(0, testhistogram3_bucket)
{start="positive"} 0 {start="positive"} 0
{start="negative"} -0.25 {start="negative"} -0.25
eval_with_nhcb instant at 50m histogram_quantile(0.25, testhistogram3_bucket) eval instant at 50m histogram_quantile(0.25, testhistogram3_bucket)
{start="positive"} 0.055 {start="positive"} 0.055
{start="negative"} -0.225 {start="negative"} -0.225
eval_with_nhcb instant at 50m histogram_quantile(0.5, testhistogram3_bucket) eval instant at 50m histogram_quantile(0.5, testhistogram3_bucket)
{start="positive"} 0.125 {start="positive"} 0.125
{start="negative"} -0.2 {start="negative"} -0.2
eval_with_nhcb instant at 50m histogram_quantile(0.75, testhistogram3_bucket) eval instant at 50m histogram_quantile(0.75, testhistogram3_bucket)
{start="positive"} 0.45 {start="positive"} 0.45
{start="negative"} -0.15 {start="negative"} -0.15
eval_with_nhcb instant at 50m histogram_quantile(1, testhistogram3_bucket) eval instant at 50m histogram_quantile(1, testhistogram3_bucket)
{start="positive"} 1 {start="positive"} 1
{start="negative"} -0.1 {start="negative"} -0.1
# Quantile too low. # Quantile too low.
eval_with_nhcb_warn instant at 50m histogram_quantile(-0.1, testhistogram_bucket) eval_warn instant at 50m histogram_quantile(-0.1, testhistogram_bucket)
{start="positive"} -Inf {start="positive"} -Inf
{start="negative"} -Inf {start="negative"} -Inf
# Quantile too high. # Quantile too high.
eval_with_nhcb_warn instant at 50m histogram_quantile(1.01, testhistogram_bucket) eval_warn instant at 50m histogram_quantile(1.01, testhistogram_bucket)
{start="positive"} +Inf {start="positive"} +Inf
{start="negative"} +Inf {start="negative"} +Inf
# Quantile invalid. # Quantile invalid.
eval_with_nhcb_warn instant at 50m histogram_quantile(NaN, testhistogram_bucket) eval_warn instant at 50m histogram_quantile(NaN, testhistogram_bucket)
{start="positive"} NaN {start="positive"} NaN
{start="negative"} NaN {start="negative"} NaN
# Quantile value in lowest bucket. # Quantile value in lowest bucket.
eval_with_nhcb instant at 50m histogram_quantile(0, testhistogram_bucket) eval instant at 50m histogram_quantile(0, testhistogram_bucket)
{start="positive"} 0 {start="positive"} 0
{start="negative"} -0.2 {start="negative"} -0.2
# Quantile value in highest bucket. # Quantile value in highest bucket.
eval_with_nhcb instant at 50m histogram_quantile(1, testhistogram_bucket) eval instant at 50m histogram_quantile(1, testhistogram_bucket)
{start="positive"} 1 {start="positive"} 1
{start="negative"} 0.3 {start="negative"} 0.3
# Finally some useful quantiles. # Finally some useful quantiles.
eval_with_nhcb instant at 50m histogram_quantile(0.2, testhistogram_bucket) eval instant at 50m histogram_quantile(0.2, testhistogram_bucket)
{start="positive"} 0.048 {start="positive"} 0.048
{start="negative"} -0.2 {start="negative"} -0.2
eval_with_nhcb instant at 50m histogram_quantile(0.5, testhistogram_bucket) eval instant at 50m histogram_quantile(0.5, testhistogram_bucket)
{start="positive"} 0.15 {start="positive"} 0.15
{start="negative"} -0.15 {start="negative"} -0.15
eval_with_nhcb instant at 50m histogram_quantile(0.8, testhistogram_bucket) eval instant at 50m histogram_quantile(0.8, testhistogram_bucket)
{start="positive"} 0.72 {start="positive"} 0.72
{start="negative"} 0.3 {start="negative"} 0.3
# More realistic with rates. # More realistic with rates.
eval_with_nhcb instant at 50m histogram_quantile(0.2, rate(testhistogram_bucket[5m])) eval instant at 50m histogram_quantile(0.2, rate(testhistogram_bucket[5m]))
{start="positive"} 0.048 {start="positive"} 0.048
{start="negative"} -0.2 {start="negative"} -0.2
eval_with_nhcb instant at 50m histogram_quantile(0.5, rate(testhistogram_bucket[5m])) eval instant at 50m histogram_quantile(0.5, rate(testhistogram_bucket[5m]))
{start="positive"} 0.15 {start="positive"} 0.15
{start="negative"} -0.15 {start="negative"} -0.15
eval_with_nhcb instant at 50m histogram_quantile(0.8, rate(testhistogram_bucket[5m])) eval instant at 50m histogram_quantile(0.8, rate(testhistogram_bucket[5m]))
{start="positive"} 0.72 {start="positive"} 0.72
{start="negative"} 0.3 {start="negative"} 0.3
# Want results exactly in the middle of the bucket. # Want results exactly in the middle of the bucket.
eval_with_nhcb instant at 7m histogram_quantile(1./6., testhistogram2_bucket) eval instant at 7m histogram_quantile(1./6., testhistogram2_bucket)
{} 1 {} 1
eval_with_nhcb instant at 7m histogram_quantile(0.5, testhistogram2_bucket) eval instant at 7m histogram_quantile(0.5, testhistogram2_bucket)
{} 3 {} 3
eval_with_nhcb instant at 7m histogram_quantile(5./6., testhistogram2_bucket) eval instant at 7m histogram_quantile(5./6., testhistogram2_bucket)
{} 5 {} 5
eval_with_nhcb instant at 47m histogram_quantile(1./6., rate(testhistogram2_bucket[15m])) eval instant at 47m histogram_quantile(1./6., rate(testhistogram2_bucket[15m]))
{} 1 {} 1
eval_with_nhcb instant at 47m histogram_quantile(0.5, rate(testhistogram2_bucket[15m])) eval instant at 47m histogram_quantile(0.5, rate(testhistogram2_bucket[15m]))
{} 3 {} 3
eval_with_nhcb instant at 47m histogram_quantile(5./6., rate(testhistogram2_bucket[15m])) eval instant at 47m histogram_quantile(5./6., rate(testhistogram2_bucket[15m]))
{} 5 {} 5
# Aggregated histogram: Everything in one. # Aggregated histogram: Everything in one.
eval_with_nhcb instant at 50m histogram_quantile(0.3, sum(rate(request_duration_seconds_bucket[5m])) by (le)) eval instant at 50m histogram_quantile(0.3, sum(rate(request_duration_seconds_bucket[5m])) by (le))
{} 0.075 {} 0.075
eval_with_nhcb instant at 50m histogram_quantile(0.5, sum(rate(request_duration_seconds_bucket[5m])) by (le)) eval instant at 50m histogram_quantile(0.5, sum(rate(request_duration_seconds_bucket[5m])) by (le))
{} 0.1277777777777778 {} 0.1277777777777778
# Aggregated histogram: Everything in one. Now with avg, which does not change anything. # Aggregated histogram: Everything in one. Now with avg, which does not change anything.
eval_with_nhcb instant at 50m histogram_quantile(0.3, avg(rate(request_duration_seconds_bucket[5m])) by (le)) eval instant at 50m histogram_quantile(0.3, avg(rate(request_duration_seconds_bucket[5m])) by (le))
{} 0.075 {} 0.075
eval_with_nhcb instant at 50m histogram_quantile(0.5, avg(rate(request_duration_seconds_bucket[5m])) by (le)) eval instant at 50m histogram_quantile(0.5, avg(rate(request_duration_seconds_bucket[5m])) by (le))
{} 0.12777777777777778 {} 0.12777777777777778
# Aggregated histogram: By instance. # Aggregated histogram: By instance.
eval_with_nhcb instant at 50m histogram_quantile(0.3, sum(rate(request_duration_seconds_bucket[5m])) by (le, instance)) eval instant at 50m histogram_quantile(0.3, sum(rate(request_duration_seconds_bucket[5m])) by (le, instance))
{instance="ins1"} 0.075 {instance="ins1"} 0.075
{instance="ins2"} 0.075 {instance="ins2"} 0.075
eval_with_nhcb instant at 50m histogram_quantile(0.5, sum(rate(request_duration_seconds_bucket[5m])) by (le, instance)) eval instant at 50m histogram_quantile(0.5, sum(rate(request_duration_seconds_bucket[5m])) by (le, instance))
{instance="ins1"} 0.1333333333 {instance="ins1"} 0.1333333333
{instance="ins2"} 0.125 {instance="ins2"} 0.125
# Aggregated histogram: By job. # Aggregated histogram: By job.
eval_with_nhcb instant at 50m histogram_quantile(0.3, sum(rate(request_duration_seconds_bucket[5m])) by (le, job)) eval instant at 50m histogram_quantile(0.3, sum(rate(request_duration_seconds_bucket[5m])) by (le, job))
{job="job1"} 0.1 {job="job1"} 0.1
{job="job2"} 0.0642857142857143 {job="job2"} 0.0642857142857143
eval_with_nhcb instant at 50m histogram_quantile(0.5, sum(rate(request_duration_seconds_bucket[5m])) by (le, job)) eval instant at 50m histogram_quantile(0.5, sum(rate(request_duration_seconds_bucket[5m])) by (le, job))
{job="job1"} 0.14 {job="job1"} 0.14
{job="job2"} 0.1125 {job="job2"} 0.1125
# Aggregated histogram: By job and instance. # Aggregated histogram: By job and instance.
eval_with_nhcb instant at 50m histogram_quantile(0.3, sum(rate(request_duration_seconds_bucket[5m])) by (le, job, instance)) eval instant at 50m histogram_quantile(0.3, sum(rate(request_duration_seconds_bucket[5m])) by (le, job, instance))
{instance="ins1", job="job1"} 0.11 {instance="ins1", job="job1"} 0.11
{instance="ins2", job="job1"} 0.09 {instance="ins2", job="job1"} 0.09
{instance="ins1", job="job2"} 0.06 {instance="ins1", job="job2"} 0.06
{instance="ins2", job="job2"} 0.0675 {instance="ins2", job="job2"} 0.0675
eval_with_nhcb instant at 50m histogram_quantile(0.5, sum(rate(request_duration_seconds_bucket[5m])) by (le, job, instance)) eval instant at 50m histogram_quantile(0.5, sum(rate(request_duration_seconds_bucket[5m])) by (le, job, instance))
{instance="ins1", job="job1"} 0.15 {instance="ins1", job="job1"} 0.15
{instance="ins2", job="job1"} 0.1333333333333333 {instance="ins2", job="job1"} 0.1333333333333333
{instance="ins1", job="job2"} 0.1 {instance="ins1", job="job2"} 0.1
{instance="ins2", job="job2"} 0.1166666666666667 {instance="ins2", job="job2"} 0.1166666666666667
# The unaggregated histogram for comparison. Same result as the previous one. # The unaggregated histogram for comparison. Same result as the previous one.
eval_with_nhcb instant at 50m histogram_quantile(0.3, rate(request_duration_seconds_bucket[5m])) eval instant at 50m histogram_quantile(0.3, rate(request_duration_seconds_bucket[5m]))
{instance="ins1", job="job1"} 0.11 {instance="ins1", job="job1"} 0.11
{instance="ins2", job="job1"} 0.09 {instance="ins2", job="job1"} 0.09
{instance="ins1", job="job2"} 0.06 {instance="ins1", job="job2"} 0.06
{instance="ins2", job="job2"} 0.0675 {instance="ins2", job="job2"} 0.0675
eval_with_nhcb instant at 50m histogram_quantile(0.5, rate(request_duration_seconds_bucket[5m])) eval instant at 50m histogram_quantile(0.5, rate(request_duration_seconds_bucket[5m]))
{instance="ins1", job="job1"} 0.15 {instance="ins1", job="job1"} 0.15
{instance="ins2", job="job1"} 0.13333333333333333 {instance="ins2", job="job1"} 0.13333333333333333
{instance="ins1", job="job2"} 0.1 {instance="ins1", job="job2"} 0.1
@ -287,11 +287,11 @@ eval instant at 50m histogram_quantile(0.5, rate(mixed[5m]))
{instance="ins1", job="job1"} 0.2 {instance="ins1", job="job1"} 0.2
{instance="ins2", job="job1"} NaN {instance="ins2", job="job1"} NaN
eval_with_nhcb instant at 50m histogram_quantile(0.75, rate(mixed_bucket[5m])) eval instant at 50m histogram_quantile(0.75, rate(mixed_bucket[5m]))
{instance="ins1", job="job1"} 0.2 {instance="ins1", job="job1"} 0.2
{instance="ins2", job="job1"} NaN {instance="ins2", job="job1"} NaN
eval_with_nhcb instant at 50m histogram_quantile(1, rate(mixed_bucket[5m])) eval instant at 50m histogram_quantile(1, rate(mixed_bucket[5m]))
{instance="ins1", job="job1"} 0.2 {instance="ins1", job="job1"} 0.2
{instance="ins2", job="job1"} NaN {instance="ins2", job="job1"} NaN
@ -300,7 +300,7 @@ load_with_nhcb 5m
empty_bucket{le="0.2", job="job1", instance="ins1"} 0x10 empty_bucket{le="0.2", job="job1", instance="ins1"} 0x10
empty_bucket{le="+Inf", job="job1", instance="ins1"} 0x10 empty_bucket{le="+Inf", job="job1", instance="ins1"} 0x10
eval_with_nhcb instant at 50m histogram_quantile(0.2, rate(empty_bucket[5m])) eval instant at 50m histogram_quantile(0.2, rate(empty_bucket[5m]))
{instance="ins1", job="job1"} NaN {instance="ins1", job="job1"} NaN
# Load a duplicate histogram with a different name to test failure scenario on multiple histograms with the same label set # Load a duplicate histogram with a different name to test failure scenario on multiple histograms with the same label set
@ -310,4 +310,4 @@ load_with_nhcb 5m
request_duration_seconds2_bucket{job="job1", instance="ins1", le="0.2"} 0+3x10 request_duration_seconds2_bucket{job="job1", instance="ins1", le="0.2"} 0+3x10
request_duration_seconds2_bucket{job="job1", instance="ins1", le="+Inf"} 0+4x10 request_duration_seconds2_bucket{job="job1", instance="ins1", le="+Inf"} 0+4x10
eval_with_nhcb_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*_bucket$"})