Skip to content

Conversation

@tcp13equals2
Copy link
Contributor

@tcp13equals2 tcp13equals2 commented Dec 31, 2025

What this PR does

Now that MQE supports delayed name removal, it is possible to include the metric name in histogram_quantile() warning and info annotations.

This brings parity to the Prometheus implementation.

The metric names are only included in the relevant warning/info annotations if EnableDelayedNameRemoval is enabled.

Which issue(s) this PR fixes or relates to

Fixes #3299

Checklist

  • [x ] Tests updated.
  • Documentation added.
  • [ x] CHANGELOG.md updated - the order of entries should be [CHANGE], [FEATURE], [ENHANCEMENT], [BUGFIX]. If changelog entry is not needed, please add the changelog-not-needed label to the PR.
  • about-versioning.md updated with experimental features.

Note

Adds metric name to histogram_quantile warning/info annotations when delayed __name__ removal is enabled, aligning with Prometheus.

  • Annotation logic: conditionally include metric name via new getMetricNameForSeries and plumb enableDelayedNameRemoval through histogram operators
  • Tests: extend annotation tests to run with both delayed name removal on/off; add expected*DelayedNameRemovalEnabled fields and new testdata for both modes; update engine tests to select appropriate engines; skip optimization tests for delayed_name_removal_enabled
  • Upstream test adjustments: comment out unsupported native histogram NaN quantile cases in streaming engine tests
  • Changelog: add enhancement entry for including metric name in histogram_quantile annotations when delayed name removal is enabled

Written by Cursor Bugbot for commit b0a10e2. This will update automatically on new commits. Configure here.

@tcp13equals2 tcp13equals2 marked this pull request as ready for review January 2, 2026 00:15
@tcp13equals2 tcp13equals2 requested a review from a team as a code owner January 2, 2026 00:15
func (q *histogramQuantile) ComputeNativeHistogramResult(pointIndex int, seriesIndex int, h *histogram.FloatHistogram) (float64, annotations.Annotations) {
ph := q.phValues.Samples[pointIndex].F
return promql.HistogramQuantile(ph, h, q.innerSeriesMetricNames.GetMetricNameForSeries(seriesIndex), q.innerExpressionPosition)
return promql.HistogramQuantile(ph, h, q.getMetricNameForSeries(seriesIndex), q.innerExpressionPosition)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

histogram_fraction ignores enableDelayedNameRemoval flag unlike histogram_quantile

The histogramFraction struct was not updated to include an enableDelayedNameRemoval field and corresponding getMetricNameForSeries method like histogramQuantile was. In ComputeNativeHistogramResult, histogram_fraction directly calls f.innerSeriesMetricNames.GetMetricNameForSeries(seriesIndex) unconditionally, while histogram_quantile now uses q.getMetricNameForSeries(seriesIndex) which respects the delayed name removal setting. This creates inconsistent behavior where histogram_fraction always includes metric names in annotations regardless of the enableDelayedNameRemoval flag, contradicting the PR's stated goal that metric names are "only included...if EnableDelayedNameRemoval is enabled."

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR relates only to histogram_quantile

Copy link
Contributor

@fionaliao fionaliao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have these test cases been disabled? Weren't they previously passing?


t.Run("Mimir's engine", func(t *testing.T) {
if strings.Contains(testFile, "name_label_dropping") {
if strings.Contains(testFile, "name_label_dropping") || strings.Contains(testFile, "delayed_name_removal_enabled") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we bring this condition out of the two t.Run calls (here and on line 264 below), so that we ensure that we consistently use / don't use engines with delayed name removal?

data string
expr string
expectedWarningAnnotations []string
// an alternate string for when delayed name removal is enabled.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] This allows more than just one string.

Suggested change
// an alternate string for when delayed name removal is enabled.
// an alternate set of annotations for when delayed name removal is enabled.

// if not set the test will fall back to expectedWarningAnnotations
expectedWarningAnnotationsDelayedNameRemovalEnabled []string
expectedInfoAnnotations []string
// an alternate string for when delayed name removal is enabled.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] This allows more than just one string.

Suggested change
// an alternate string for when delayed name removal is enabled.
// an alternate set of annotations for when delayed name removal is enabled.

Comment on lines +2282 to +2283
for _, delayedNameRemovalEnabled := range []bool{true, false} {
results := make([]*promql.Result, 0, 2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should call t.Run here with a name that makes it clear if delayed name removal was enabled or disabled. (Otherwise we'll get two nested tests for each engine, both with the same name, eg. "Mimir's engine".)

Comment on lines +2282 to +2285
for _, delayedNameRemovalEnabled := range []bool{true, false} {
results := make([]*promql.Result, 0, 2)

for engineName, engine := range engines[delayedNameRemovalEnabled] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for _, delayedNameRemovalEnabled := range []bool{true, false} {
results := make([]*promql.Result, 0, 2)
for engineName, engine := range engines[delayedNameRemovalEnabled] {
for engines, delayedNameRemovalEnabled := range engines {
results := make([]*promql.Result, 0, 2)
for engineName, engine := range engines {


// create 2 sets of engines - one with EnableDelayedNameRemoval=true and the 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
engines := make(map[bool]map[string]promql.QueryEngine, 2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be even simpler (and help reduce some nesting below) to define engines something like this:

Suggested change
engines := make(map[bool]map[string]promql.QueryEngine, 2)
engines := []struct{
engine promql.QueryEngine
name string // eg. "Mimir's engine without delayed name removal"
delayedNameRemovalEnabled bool
}{}

// The name is dropped even if the function is the first one invoked on the vector selector.
// Mimir doesn't have delayed __name__ removal, so to stay close to prometheus, we never display the label in some annotations and warnings.
// This is only used for backwards compatibility when delayed __name__ removal is not enabled.
intentionallyEmptyMetricName = ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given this is only referenced in one place (getMetricNameForSeries) now, should we move this constant and the comment into there?

We could probably also drop the constant and just move the comment to explain why we return an empty value.

Copy link
Contributor

@tacole02 tacole02 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changelog LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants