-
Notifications
You must be signed in to change notification settings - Fork 697
include metric name in annotations from histogram_quantile if delayed… #13905
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 12 commits
e92c5fc
f941eb3
c3abc4d
2d76138
2d6fe0a
b0a10e2
22cad81
eb62803
cb68b15
73819a8
71b15b9
3bbefd1
fe279ba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -249,13 +249,17 @@ func TestOurTestCases(t *testing.T) { | |
|
|
||
| testScript := string(b) | ||
|
|
||
| t.Run("Mimir's engine", func(t *testing.T) { | ||
| if strings.Contains(testFile, "name_label_dropping") { | ||
| promqltest.RunTest(t, testScript, mimirEngineWithDelayedNameRemoval) | ||
| return | ||
| } | ||
| mimirEngineToTest := mimirEngine | ||
| prometheusEngineToTest := prometheusEngine | ||
|
|
||
| // switch to the alternate engines if we need delayed name removal | ||
| if strings.Contains(testFile, "name_label_dropping") || strings.Contains(testFile, "delayed_name_removal_enabled") { | ||
| mimirEngineToTest = mimirEngineWithDelayedNameRemoval | ||
| prometheusEngineToTest = prometheusEngineWithDelayedNameRemoval | ||
| } | ||
|
|
||
| promqltest.RunTest(t, testScript, mimirEngine) | ||
| t.Run("Mimir's engine", func(t *testing.T) { | ||
| promqltest.RunTest(t, testScript, mimirEngineToTest) | ||
| }) | ||
|
|
||
| // Run the tests against Prometheus' engine to ensure our test cases are valid. | ||
|
|
@@ -264,12 +268,7 @@ func TestOurTestCases(t *testing.T) { | |
| t.Skip("disabled for Prometheus' engine due to bug in Prometheus' engine") | ||
| } | ||
|
|
||
| if strings.Contains(testFile, "name_label_dropping") { | ||
| promqltest.RunTest(t, testScript, prometheusEngineWithDelayedNameRemoval) | ||
| return | ||
| } | ||
|
|
||
| promqltest.RunTest(t, testScript, prometheusEngine) | ||
| promqltest.RunTest(t, testScript, prometheusEngineToTest) | ||
| }) | ||
| }) | ||
| } | ||
|
|
@@ -2204,32 +2203,69 @@ func (t *timeoutTestingQueryTracker) Close() error { | |
| } | ||
|
|
||
| type annotationTestCase struct { | ||
| data string | ||
| expr string | ||
| expectedWarningAnnotations []string | ||
| expectedInfoAnnotations []string | ||
| data string | ||
| expr string | ||
| expectedWarningAnnotations []string | ||
| expectedInfoAnnotations []string | ||
|
|
||
| // an alternate set of annotations for when delayed name removal is enabled. | ||
| // if not set the test will fall back to expectedWarningAnnotations / expectedInfoAnnotations | ||
| expectedWarningAnnotationsDelayedNameRemovalEnabled []string | ||
| expectedInfoAnnotationsDelayedNameRemovalEnabled []string | ||
|
|
||
| skipComparisonWithPrometheusReason string | ||
| instantEvaluationTimestamp *time.Time | ||
| } | ||
|
|
||
| func (a annotationTestCase) getExpectedInfoAnnotations(delayedNameRemovalEnabled bool) []string { | ||
| if delayedNameRemovalEnabled && a.expectedInfoAnnotationsDelayedNameRemovalEnabled != nil { | ||
| return a.expectedInfoAnnotationsDelayedNameRemovalEnabled | ||
| } | ||
| return a.expectedInfoAnnotations | ||
| } | ||
|
|
||
| func (a annotationTestCase) getExpectedWarningAnnotations(delayedNameRemovalEnabled bool) []string { | ||
| if delayedNameRemovalEnabled && a.expectedWarningAnnotationsDelayedNameRemovalEnabled != nil { | ||
| return a.expectedWarningAnnotationsDelayedNameRemovalEnabled | ||
| } | ||
| return a.expectedWarningAnnotations | ||
| } | ||
|
|
||
| func runAnnotationTests(t *testing.T, testCases map[string]annotationTestCase) { | ||
| startT := timestamp.Time(0).Add(time.Minute) | ||
| step := time.Minute | ||
| endT := startT.Add(2 * step) | ||
|
|
||
| opts := NewTestEngineOpts() | ||
| planner, err := NewQueryPlanner(opts, NewMaximumSupportedVersionQueryPlanVersionProvider()) | ||
| require.NoError(t, err) | ||
| mimirEngine, err := NewEngine(opts, NewStaticQueryLimitsProvider(0), stats.NewQueryMetrics(nil), planner) | ||
| require.NoError(t, err) | ||
| prometheusEngine := promql.NewEngine(opts.CommonOpts) | ||
|
|
||
| const prometheusEngineName = "Prometheus' engine" | ||
| engines := map[string]promql.QueryEngine{ | ||
| "Mimir's engine": mimirEngine, | ||
| const mimirEngineName = "Mimir's engine" | ||
|
|
||
| // create 2 sets of engines - a Mimir and Prometheus engine each with EnableDelayedNameRemoval=true and other with EnableDelayedNameRemoval=false | ||
| // there are some histogram annotation test cases which will emit a different warning/info annotation string depending on the delayed name removal setting | ||
| engineSets := make([]struct { | ||
| mimirEngine promql.QueryEngine | ||
| prometheusEngine promql.QueryEngine | ||
| delayedNameRemovalEnabled bool | ||
| }, 0, 2) | ||
|
|
||
| for _, delayedNameRemovalEnabled := range []bool{true, false} { | ||
| opts := NewTestEngineOpts() | ||
| opts.CommonOpts.EnableDelayedNameRemoval = delayedNameRemovalEnabled | ||
|
|
||
| // Compare against Prometheus' engine to verify our test cases are valid. | ||
| prometheusEngineName: prometheusEngine, | ||
| planner, err := NewQueryPlanner(opts, NewMaximumSupportedVersionQueryPlanVersionProvider()) | ||
| require.NoError(t, err) | ||
| mimirEngine, err := NewEngine(opts, NewStaticQueryLimitsProvider(0), stats.NewQueryMetrics(nil), planner) | ||
| require.NoError(t, err) | ||
| prometheusEngine := promql.NewEngine(opts.CommonOpts) | ||
|
|
||
| engineSets = append(engineSets, struct { | ||
| mimirEngine promql.QueryEngine | ||
| prometheusEngine promql.QueryEngine | ||
| delayedNameRemovalEnabled bool | ||
| }{ | ||
| mimirEngine: mimirEngine, | ||
| prometheusEngine: prometheusEngine, | ||
| delayedNameRemovalEnabled: delayedNameRemovalEnabled, | ||
| }) | ||
| } | ||
|
|
||
| for name, testCase := range testCases { | ||
|
|
@@ -2253,36 +2289,43 @@ func runAnnotationTests(t *testing.T, testCases map[string]annotationTestCase) { | |
| } | ||
|
|
||
| for queryType, generator := range queryTypes { | ||
| t.Run(queryType, func(t *testing.T) { | ||
| results := make([]*promql.Result, 0, 2) | ||
|
|
||
| for engineName, engine := range engines { | ||
| if engineName == prometheusEngineName && testCase.skipComparisonWithPrometheusReason != "" { | ||
| t.Logf("Skipping comparison with Prometheus' engine: %v", testCase.skipComparisonWithPrometheusReason) | ||
| continue | ||
| for _, engineSet := range engineSets { | ||
| subTestName := fmt.Sprintf("%s - delayed name removal enabled=%t", queryType, engineSet.delayedNameRemovalEnabled) | ||
| t.Run(subTestName, func(t *testing.T) { | ||
| results := make([]*promql.Result, 0, 2) | ||
|
|
||
| for _, engine := range []promql.QueryEngine{engineSet.mimirEngine, engineSet.prometheusEngine} { | ||
| if engine == engineSet.prometheusEngine && testCase.skipComparisonWithPrometheusReason != "" { | ||
| t.Logf("Skipping comparison with Prometheus' engine: %v", testCase.skipComparisonWithPrometheusReason) | ||
| continue | ||
| } | ||
| engineName := mimirEngineName | ||
| if engine == engineSet.prometheusEngine { | ||
| engineName = prometheusEngineName | ||
| } | ||
| t.Run(engineName, func(t *testing.T) { | ||
| query, err := generator(engine) | ||
| require.NoError(t, err) | ||
| t.Cleanup(query.Close) | ||
|
|
||
| res := query.Exec(context.Background()) | ||
| require.NoError(t, res.Err) | ||
| results = append(results, res) | ||
|
|
||
| warnings, infos := res.Warnings.AsStrings(testCase.expr, 0, 0) | ||
| require.ElementsMatch(t, testCase.getExpectedWarningAnnotations(engineSet.delayedNameRemovalEnabled), warnings) | ||
| require.ElementsMatch(t, testCase.getExpectedInfoAnnotations(engineSet.delayedNameRemovalEnabled), infos) | ||
| }) | ||
| } | ||
| t.Run(engineName, func(t *testing.T) { | ||
| query, err := generator(engine) | ||
| require.NoError(t, err) | ||
| t.Cleanup(query.Close) | ||
|
|
||
| res := query.Exec(context.Background()) | ||
| require.NoError(t, res.Err) | ||
| results = append(results, res) | ||
|
|
||
| warnings, infos := res.Warnings.AsStrings(testCase.expr, 0, 0) | ||
| require.ElementsMatch(t, testCase.expectedWarningAnnotations, warnings) | ||
| require.ElementsMatch(t, testCase.expectedInfoAnnotations, infos) | ||
| }) | ||
| } | ||
|
|
||
| // If both results are available, compare them (sometimes we skip prometheus) | ||
| if len(results) == 2 { | ||
| // We do this extra comparison to ensure that we don't skip a series that may be outputted during a warning | ||
| // or vice-versa where no result may be expected etc. | ||
| mqetest.RequireEqualResults(t, testCase.expr, results[0], results[1], false) | ||
| } | ||
| }) | ||
| // If both results are available, compare them (sometimes we skip prometheus) | ||
| if len(results) == 2 { | ||
| // We do this extra comparison to ensure that we don't skip a series that may be outputted during a warning | ||
| // or vice-versa where no result may be expected etc. | ||
| mqetest.RequireEqualResults(t, testCase.expr, results[0], results[1], false) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
| }) | ||
| } | ||
|
|
@@ -3144,6 +3187,7 @@ func TestHistogramAnnotations(t *testing.T) { | |
| data: mixedClassicHistograms, | ||
| expr: `histogram_quantile(0.5, series{host="c"})`, | ||
| expectedWarningAnnotations: []string{`PromQL warning: bucket label "le" is missing or has a malformed value of "abc" (1:25)`}, | ||
| expectedWarningAnnotationsDelayedNameRemovalEnabled: []string{`PromQL warning: bucket label "le" is missing or has a malformed value of "abc" for metric name "series" (1:25)`}, | ||
| }, | ||
| "invalid quantile warning": { | ||
| data: mixedClassicHistograms, | ||
|
|
@@ -3154,11 +3198,13 @@ func TestHistogramAnnotations(t *testing.T) { | |
| data: mixedClassicHistograms, | ||
| expr: `histogram_quantile(0.5, series{host="a"})`, | ||
| expectedWarningAnnotations: []string{`PromQL warning: vector contains a mix of classic and native histograms (1:25)`}, | ||
| expectedWarningAnnotationsDelayedNameRemovalEnabled: []string{`PromQL warning: vector contains a mix of classic and native histograms for metric name "series" (1:25)`}, | ||
| }, | ||
| "forced monotonicity info": { | ||
| data: mixedClassicHistograms, | ||
| expr: `histogram_quantile(0.5, series{host="d"})`, | ||
| expectedInfoAnnotations: []string{`PromQL info: input to histogram_quantile needed to be fixed for monotonicity (see https://prometheus.io/docs/prometheus/latest/querying/functions/#histogram_quantile) (1:25)`}, | ||
| expectedInfoAnnotationsDelayedNameRemovalEnabled: []string{`PromQL info: input to histogram_quantile needed to be fixed for monotonicity (see https://prometheus.io/docs/prometheus/latest/querying/functions/#histogram_quantile) for metric name "series" (1:25)`}, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I realise this isn't something we can control, but I find the expression here hard to follow - the "for metric name ..." bit seems out of place after the parentheses, it fits better before the parentheses to me. Perhaps something to change upstream?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which ones do you like;
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm OK with tweaking the old structure: |
||
| }, | ||
| "both mixed classic+native histogram and invalid quantile warnings": { | ||
| data: mixedClassicHistograms, | ||
|
|
@@ -3167,6 +3213,10 @@ func TestHistogramAnnotations(t *testing.T) { | |
| `PromQL warning: vector contains a mix of classic and native histograms (1:23)`, | ||
| `PromQL warning: quantile value should be between 0 and 1, got 9 (1:20)`, | ||
| }, | ||
| expectedWarningAnnotationsDelayedNameRemovalEnabled: []string{ | ||
| `PromQL warning: vector contains a mix of classic and native histograms for metric name "series" (1:23)`, | ||
| `PromQL warning: quantile value should be between 0 and 1, got 9 (1:20)`, | ||
| }, | ||
| }, | ||
| "forced monotonicity info is not emitted when quantile is invalid": { | ||
| data: mixedClassicHistograms, | ||
|
|
@@ -3179,6 +3229,7 @@ func TestHistogramAnnotations(t *testing.T) { | |
| `, | ||
| expr: `histogram_quantile(0.5, series{})`, | ||
| expectedWarningAnnotations: []string{`PromQL warning: bucket label "le" is missing or has a malformed value of "" (1:25)`}, | ||
| expectedWarningAnnotationsDelayedNameRemovalEnabled: []string{`PromQL warning: bucket label "le" is missing or has a malformed value of "" for metric name "series" (1:25)`}, | ||
| }, | ||
| "extra entry in series without le label": { | ||
| data: ` | ||
|
|
@@ -3187,6 +3238,7 @@ func TestHistogramAnnotations(t *testing.T) { | |
| `, | ||
| expr: `histogram_quantile(0.5, series{})`, | ||
| expectedWarningAnnotations: []string{`PromQL warning: bucket label "le" is missing or has a malformed value of "" (1:25)`}, | ||
| expectedWarningAnnotationsDelayedNameRemovalEnabled: []string{`PromQL warning: bucket label "le" is missing or has a malformed value of "" for metric name "series" (1:25)`}, | ||
| }, | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.