From 516afbea6768af89b8e2d4f32bc8d8690ad9602e Mon Sep 17 00:00:00 2001 From: Sahil Rasaikar Date: Sun, 17 Aug 2025 16:18:02 +0530 Subject: [PATCH 01/14] Init Commit: fix for issue #4510 Signed-off-by: Sahil Rasaikar --- rules/alerting.go | 11 ++++++++- .../mantine-ui/src/api/responseTypes/rules.ts | 2 +- web/ui/mantine-ui/src/pages/AlertsPage.tsx | 23 ++++++++++++++++--- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/rules/alerting.go b/rules/alerting.go index 9a6ff0a113..6af3a46171 100644 --- a/rules/alerting.go +++ b/rules/alerting.go @@ -58,6 +58,8 @@ const ( // StateFiring is the state of an alert that has been active for longer than // the configured threshold duration. StateFiring + // StateUnknown is the state of an alert that has not yet been evaluated. + StateUnknown ) func (s AlertState) String() string { @@ -68,6 +70,8 @@ func (s AlertState) String() string { return "pending" case StateFiring: return "firing" + case StateUnknown: + return "unknown" } panic(fmt.Errorf("unknown alert state: %d", s)) } @@ -530,8 +534,13 @@ func (r *AlertingRule) Eval(ctx context.Context, queryOffset time.Duration, ts t } // State returns the maximum state of alert instances for this rule. -// StateFiring > StatePending > StateInactive. +// StateFiring > StatePending > StateInactive > StateUnknown. func (r *AlertingRule) State() AlertState { + // If the rule has never been evaluated, return StateUnknown + if r.GetEvaluationTimestamp().IsZero() { + return StateUnknown + } + r.activeMtx.Lock() defer r.activeMtx.Unlock() diff --git a/web/ui/mantine-ui/src/api/responseTypes/rules.ts b/web/ui/mantine-ui/src/api/responseTypes/rules.ts index ff04ad2cc9..89ce0f4acc 100644 --- a/web/ui/mantine-ui/src/api/responseTypes/rules.ts +++ b/web/ui/mantine-ui/src/api/responseTypes/rules.ts @@ -1,4 +1,4 @@ -type RuleState = "pending" | "firing" | "inactive"; +type RuleState = "pending" | "firing" | "inactive" | "unknown"; export interface Alert { labels: Record; diff --git a/web/ui/mantine-ui/src/pages/AlertsPage.tsx b/web/ui/mantine-ui/src/pages/AlertsPage.tsx index 00e6595fd4..2608117c8f 100644 --- a/web/ui/mantine-ui/src/pages/AlertsPage.tsx +++ b/web/ui/mantine-ui/src/pages/AlertsPage.tsx @@ -45,6 +45,7 @@ type AlertsPageData = { inactive: number; pending: number; firing: number; + unknown: number; }; groups: { name: string; @@ -55,6 +56,7 @@ type AlertsPageData = { inactive: number; pending: number; firing: number; + unknown: number; }; rules: { rule: AlertingRule; @@ -82,6 +84,7 @@ const buildAlertsPageData = ( inactive: 0, pending: 0, firing: 0, + unknown: 0, }, groups: [], }; @@ -92,6 +95,7 @@ const buildAlertsPageData = ( inactive: 0, pending: 0, firing: 0, + unknown: 0, }; for (const r of group.rules) { @@ -109,6 +113,10 @@ const buildAlertsPageData = ( pageData.globalCounts.pending++; groupCounts.pending++; break; + case "unknown": + pageData.globalCounts.unknown++; + groupCounts.unknown++; + break; default: throw new Error(`Unknown rule state: ${r.state}`); } @@ -239,6 +247,11 @@ export default function AlertsPage() { pending ({g.counts.pending}) )} + {g.counts.unknown > 0 && ( + + unknown ({g.counts.unknown}) + + )} {g.counts.inactive > 0 && ( inactive ({g.counts.inactive}) @@ -285,7 +298,9 @@ export default function AlertsPage() { ? panelClasses.panelHealthErr : r.counts.pending > 0 ? panelClasses.panelHealthWarn - : panelClasses.panelHealthOk + : r.rule.state === "unknown" + ? panelClasses.panelHealthUnknown + : panelClasses.panelHealthOk } > o === "inactive" ? badgeClasses.healthOk : o === "pending" ? badgeClasses.healthWarn - : badgeClasses.healthErr + : o === "firing" + ? badgeClasses.healthErr + : badgeClasses.healthUnknown } optionCount={(o) => alertsPageData.globalCounts[ From cc1e6e40f0c39f44e94f001d5f58ff975ce0b6ff Mon Sep 17 00:00:00 2001 From: Sahil Rasaikar Date: Sun, 5 Oct 2025 16:31:17 +0530 Subject: [PATCH 02/14] fix: Updates unknown state to -1,adds fix for failing test case Signed-off-by: Sahil Rasaikar --- rules/alerting.go | 13 +++++++------ rules/alerting_test.go | 2 ++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/rules/alerting.go b/rules/alerting.go index 6af3a46171..6e2dc3ffa7 100644 --- a/rules/alerting.go +++ b/rules/alerting.go @@ -50,6 +50,8 @@ const ( type AlertState int const ( + // StateUnknown is the state of an alert that has not yet been evaluated. + StateUnknown AlertState = -1 // StateInactive is the state of an alert that is neither firing nor pending. StateInactive AlertState = iota // StatePending is the state of an alert that has been active for less than @@ -58,8 +60,6 @@ const ( // StateFiring is the state of an alert that has been active for longer than // the configured threshold duration. StateFiring - // StateUnknown is the state of an alert that has not yet been evaluated. - StateUnknown ) func (s AlertState) String() string { @@ -536,13 +536,14 @@ func (r *AlertingRule) Eval(ctx context.Context, queryOffset time.Duration, ts t // State returns the maximum state of alert instances for this rule. // StateFiring > StatePending > StateInactive > StateUnknown. func (r *AlertingRule) State() AlertState { - // If the rule has never been evaluated, return StateUnknown - if r.GetEvaluationTimestamp().IsZero() { - return StateUnknown - } r.activeMtx.Lock() defer r.activeMtx.Unlock() + + // Check if the rule has been evaluated + if r.evaluationTimestamp.Load().IsZero() { + return StateUnknown + } maxState := StateInactive for _, a := range r.active { diff --git a/rules/alerting_test.go b/rules/alerting_test.go index 49817cc286..fff1d40048 100644 --- a/rules/alerting_test.go +++ b/rules/alerting_test.go @@ -85,6 +85,8 @@ func TestAlertingRuleState(t *testing.T) { for i, test := range tests { rule := NewAlertingRule(test.name, nil, 0, 0, labels.EmptyLabels(), labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil) rule.active = test.active + // Set evaluation timestamp to simulate that the rule has been evaluated + rule.SetEvaluationTimestamp(time.Now()) got := rule.State() require.Equal(t, test.want, got, "test case %d unexpected AlertState, want:%d got:%d", i, test.want, got) } From 96425ea9841874ab7385753c0dc9be1e382859ec Mon Sep 17 00:00:00 2001 From: Sahil Rasaikar Date: Sun, 5 Oct 2025 17:08:49 +0530 Subject: [PATCH 03/14] fix: linting errors Signed-off-by: Sahil Rasaikar --- rules/alerting.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/rules/alerting.go b/rules/alerting.go index 6e2dc3ffa7..74f199e9f0 100644 --- a/rules/alerting.go +++ b/rules/alerting.go @@ -536,10 +536,8 @@ func (r *AlertingRule) Eval(ctx context.Context, queryOffset time.Duration, ts t // State returns the maximum state of alert instances for this rule. // StateFiring > StatePending > StateInactive > StateUnknown. func (r *AlertingRule) State() AlertState { - r.activeMtx.Lock() defer r.activeMtx.Unlock() - // Check if the rule has been evaluated if r.evaluationTimestamp.Load().IsZero() { return StateUnknown From 8a3ec78ae8c0b5d4bec965c539761d96090afe71 Mon Sep 17 00:00:00 2001 From: Sahil Rasaikar Date: Wed, 8 Oct 2025 22:56:35 +0530 Subject: [PATCH 04/14] fix: reorder AlertState constants to start with StateUnknown, reorder String method to match constant order. Signed-off-by: Sahil Rasaikar --- rules/alerting.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rules/alerting.go b/rules/alerting.go index 74f199e9f0..b0151d7cb3 100644 --- a/rules/alerting.go +++ b/rules/alerting.go @@ -51,9 +51,9 @@ type AlertState int const ( // StateUnknown is the state of an alert that has not yet been evaluated. - StateUnknown AlertState = -1 + StateUnknown AlertState = iota // StateInactive is the state of an alert that is neither firing nor pending. - StateInactive AlertState = iota + StateInactive // StatePending is the state of an alert that has been active for less than // the configured threshold duration. StatePending @@ -64,14 +64,14 @@ const ( func (s AlertState) String() string { switch s { + case StateUnknown: + return "unknown" case StateInactive: return "inactive" case StatePending: return "pending" case StateFiring: return "firing" - case StateUnknown: - return "unknown" } panic(fmt.Errorf("unknown alert state: %d", s)) } From 7cf4b5da55682cbc9472bf61abf041fa7c9981d8 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Tue, 9 Sep 2025 08:48:50 +0200 Subject: [PATCH 05/14] OTLP: Upgrade prometheus/otlptranslator The upgrade to prometheus/otlptranslator@7f02967de014 fixes two label name translation bugs, when in legacy name translation mode: * 'key' is no longer prefixed when label names start with an underscore * Multiple consecutive underscores are combined into one Signed-off-by: Arve Knudsen --- .../remote/otlptranslator/prometheusremotewrite/helper.go | 6 +++++- .../otlptranslator/prometheusremotewrite/metrics_to_prw.go | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/storage/remote/otlptranslator/prometheusremotewrite/helper.go b/storage/remote/otlptranslator/prometheusremotewrite/helper.go index 4c50099e06..b8c7817a84 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/helper.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/helper.go @@ -88,7 +88,11 @@ func (c *PrometheusConverter) createAttributes(resource pcommon.Resource, attrib c.scratchBuilder.Sort() sortedLabels := c.scratchBuilder.Labels() - labelNamer := otlptranslator.LabelNamer{UTF8Allowed: settings.AllowUTF8} + labelNamer := otlptranslator.LabelNamer{ + UTF8Allowed: settings.AllowUTF8, + UnderscoreLabelSanitization: settings.LabelNameUnderscoreLabelSanitization, + PreserveMultipleUnderscores: settings.LabelNamePreserveMultipleUnderscores, + } if settings.AllowUTF8 { // UTF8 is allowed, so conflicts aren't possible. diff --git a/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go b/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go index 3dfd54cc9f..7083ce0885 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go @@ -54,6 +54,12 @@ type Settings struct { // PromoteScopeMetadata controls whether to promote OTel scope metadata to metric labels. PromoteScopeMetadata bool EnableTypeAndUnitLabels bool + // LabelNameUnderscoreLabelSanitization controls whether to enable prepending of 'key' to labels + // starting with '_'. Reserved labels starting with `__` are not modified. + LabelNameUnderscoreLabelSanitization bool + // LabelNamePreserveMultipleUnderscores enables preserving of multiple + // consecutive underscores in label names when AllowUTF8 is false. + LabelNamePreserveMultipleUnderscores bool } // PrometheusConverter converts from OTel write format to Prometheus remote write format. From dd3a607d2d5d67b3608dfd6d34941343d642a24d Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Thu, 16 Oct 2025 13:41:53 +0200 Subject: [PATCH 06/14] Add configuration parameters Signed-off-by: Arve Knudsen --- config/config.go | 12 +- config/config_test.go | 46 ++++- ..._underscore_sanitization_defaults.good.yml | 2 + ..._underscore_sanitization_disabled.good.yml | 3 + ...l_underscore_sanitization_enabled.good.yml | 3 + docs/configuration/configuration.md | 9 + .../prometheusremotewrite/helper.go | 4 +- .../prometheusremotewrite/helper_test.go | 170 ++++++++++++++++-- .../prometheusremotewrite/metrics_to_prw.go | 12 +- storage/remote/write_handler.go | 20 ++- 10 files changed, 254 insertions(+), 27 deletions(-) create mode 100644 config/testdata/otlp_label_underscore_sanitization_defaults.good.yml create mode 100644 config/testdata/otlp_label_underscore_sanitization_disabled.good.yml create mode 100644 config/testdata/otlp_label_underscore_sanitization_enabled.good.yml diff --git a/config/config.go b/config/config.go index 8e7afc1f2f..91b91d25fc 100644 --- a/config/config.go +++ b/config/config.go @@ -258,7 +258,9 @@ var ( // DefaultOTLPConfig is the default OTLP configuration. DefaultOTLPConfig = OTLPConfig{ - TranslationStrategy: otlptranslator.UnderscoreEscapingWithSuffixes, + TranslationStrategy: otlptranslator.UnderscoreEscapingWithSuffixes, + LabelNameUnderscoreSanitization: true, + LabelNamePreserveMultipleUnderscores: true, } ) @@ -1609,6 +1611,14 @@ type OTLPConfig struct { // PromoteScopeMetadata controls whether to promote OTel scope metadata (i.e. name, version, schema URL, and attributes) to metric labels. // As per OTel spec, the aforementioned scope metadata should be identifying, i.e. made into metric labels. PromoteScopeMetadata bool `yaml:"promote_scope_metadata,omitempty"` + // LabelNameUnderscoreSanitization controls whether to enable prepending of 'key_' to labels + // starting with '_'. Reserved labels starting with `__` are not modified. + // This is only relevant when AllowUTF8 is false (i.e., when using underscore escaping). + LabelNameUnderscoreSanitization bool `yaml:"label_name_underscore_sanitization,omitempty"` + // LabelNamePreserveMultipleUnderscores enables preserving of multiple consecutive underscores + // in label names when AllowUTF8 is false. When false, multiple consecutive underscores are + // collapsed to a single underscore during label name sanitization. + LabelNamePreserveMultipleUnderscores bool `yaml:"label_name_preserve_multiple_underscores,omitempty"` } // UnmarshalYAML implements the yaml.Unmarshaler interface. diff --git a/config/config_test.go b/config/config_test.go index 1f093c7959..d729d2a6aa 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -175,7 +175,9 @@ var expectedConf = &Config{ PromoteResourceAttributes: []string{ "k8s.cluster.name", "k8s.job.name", "k8s.namespace.name", }, - TranslationStrategy: otlptranslator.UnderscoreEscapingWithSuffixes, + TranslationStrategy: otlptranslator.UnderscoreEscapingWithSuffixes, + LabelNameUnderscoreSanitization: true, + LabelNamePreserveMultipleUnderscores: true, }, RemoteReadConfigs: []*RemoteReadConfig{ @@ -1842,6 +1844,48 @@ func TestOTLPPromoteScopeMetadata(t *testing.T) { }) } +func TestOTLPLabelUnderscoreSanitization(t *testing.T) { + t.Run("defaults to true", func(t *testing.T) { + conf, err := LoadFile(filepath.Join("testdata", "otlp_label_underscore_sanitization_defaults.good.yml"), false, promslog.NewNopLogger()) + require.NoError(t, err) + + // Test that default values are true + require.True(t, conf.OTLPConfig.LabelNameUnderscoreSanitization) + require.True(t, conf.OTLPConfig.LabelNamePreserveMultipleUnderscores) + }) + + t.Run("explicit enabled", func(t *testing.T) { + conf, err := LoadFile(filepath.Join("testdata", "otlp_label_underscore_sanitization_enabled.good.yml"), false, promslog.NewNopLogger()) + require.NoError(t, err) + + out, err := yaml.Marshal(conf) + require.NoError(t, err) + var got Config + require.NoError(t, yaml.UnmarshalStrict(out, &got)) + + require.True(t, got.OTLPConfig.LabelNameUnderscoreSanitization) + require.True(t, got.OTLPConfig.LabelNamePreserveMultipleUnderscores) + }) + + t.Run("explicit disabled", func(t *testing.T) { + conf, err := LoadFile(filepath.Join("testdata", "otlp_label_underscore_sanitization_disabled.good.yml"), false, promslog.NewNopLogger()) + require.NoError(t, err) + + // When explicitly set to false, they should be false + require.False(t, conf.OTLPConfig.LabelNameUnderscoreSanitization) + require.False(t, conf.OTLPConfig.LabelNamePreserveMultipleUnderscores) + }) + + t.Run("empty config uses defaults", func(t *testing.T) { + conf, err := LoadFile(filepath.Join("testdata", "otlp_empty.yml"), false, promslog.NewNopLogger()) + require.NoError(t, err) + + // Empty config should use default values (true) + require.True(t, conf.OTLPConfig.LabelNameUnderscoreSanitization) + require.True(t, conf.OTLPConfig.LabelNamePreserveMultipleUnderscores) + }) +} + func TestOTLPAllowUTF8(t *testing.T) { t.Run("good config - NoUTF8EscapingWithSuffixes", func(t *testing.T) { fpath := filepath.Join("testdata", "otlp_allow_utf8.good.yml") diff --git a/config/testdata/otlp_label_underscore_sanitization_defaults.good.yml b/config/testdata/otlp_label_underscore_sanitization_defaults.good.yml new file mode 100644 index 0000000000..3b1e9796d3 --- /dev/null +++ b/config/testdata/otlp_label_underscore_sanitization_defaults.good.yml @@ -0,0 +1,2 @@ +otlp: + promote_resource_attributes: ["service.name"] diff --git a/config/testdata/otlp_label_underscore_sanitization_disabled.good.yml b/config/testdata/otlp_label_underscore_sanitization_disabled.good.yml new file mode 100644 index 0000000000..f8fe4ea669 --- /dev/null +++ b/config/testdata/otlp_label_underscore_sanitization_disabled.good.yml @@ -0,0 +1,3 @@ +otlp: + label_name_underscore_sanitization: false + label_name_preserve_multiple_underscores: false diff --git a/config/testdata/otlp_label_underscore_sanitization_enabled.good.yml b/config/testdata/otlp_label_underscore_sanitization_enabled.good.yml new file mode 100644 index 0000000000..8ce347495e --- /dev/null +++ b/config/testdata/otlp_label_underscore_sanitization_enabled.good.yml @@ -0,0 +1,3 @@ +otlp: + label_name_underscore_sanitization: true + label_name_preserve_multiple_underscores: true diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index b3ea571b80..451af231c5 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -222,6 +222,15 @@ otlp: # Enables promotion of OTel scope metadata (i.e. name, version, schema URL, and attributes) to metric labels. # This is disabled by default for backwards compatibility, but according to OTel spec, scope metadata _should_ be identifying, i.e. translated to metric labels. [ promote_scope_metadata: | default = false ] + # Controls whether to enable prepending of 'key_' to labels starting with '_'. + # Reserved labels starting with '__' are not modified. + # This is only relevant when translation_strategy uses underscore escaping + # (e.g., "UnderscoreEscapingWithSuffixes" or "UnderscoreEscapingWithoutSuffixes"). + [ label_name_underscore_sanitization: | default = true ] + # Enables preserving of multiple consecutive underscores in label names when + # translation_strategy uses underscore escaping. When true (default), multiple + # consecutive underscores are preserved during label name sanitization. + [ label_name_preserve_multiple_underscores: | default = true ] # Settings related to the remote read feature. remote_read: diff --git a/storage/remote/otlptranslator/prometheusremotewrite/helper.go b/storage/remote/otlptranslator/prometheusremotewrite/helper.go index b8c7817a84..9f73bb1a49 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/helper.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/helper.go @@ -90,7 +90,7 @@ func (c *PrometheusConverter) createAttributes(resource pcommon.Resource, attrib labelNamer := otlptranslator.LabelNamer{ UTF8Allowed: settings.AllowUTF8, - UnderscoreLabelSanitization: settings.LabelNameUnderscoreLabelSanitization, + UnderscoreLabelSanitization: settings.LabelNameUnderscoreSanitization, PreserveMultipleUnderscores: settings.LabelNamePreserveMultipleUnderscores, } @@ -122,7 +122,7 @@ func (c *PrometheusConverter) createAttributes(resource pcommon.Resource, attrib } } - err := settings.PromoteResourceAttributes.addPromotedAttributes(c.builder, resourceAttrs, settings.AllowUTF8) + err := settings.PromoteResourceAttributes.addPromotedAttributes(c.builder, resourceAttrs, settings.AllowUTF8, settings.LabelNameUnderscoreSanitization, settings.LabelNamePreserveMultipleUnderscores) if err != nil { return labels.EmptyLabels(), err } diff --git a/storage/remote/otlptranslator/prometheusremotewrite/helper_test.go b/storage/remote/otlptranslator/prometheusremotewrite/helper_test.go index 9ecb2c15f7..948bd8ca7d 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/helper_test.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/helper_test.go @@ -67,15 +67,35 @@ func TestCreateAttributes(t *testing.T) { attrs.PutStr("metric-attr", "metric value") attrs.PutStr("metric-attr-other", "metric value other") + // Setup resources with underscores for sanitization tests + resourceAttrsWithUnderscores := map[string]string{ + "service.name": "service name", + "service.instance.id": "service ID", + "_private": "private value", + "__reserved__": "reserved value", + "label___multi": "multi value", + } + resourceWithUnderscores := pcommon.NewResource() + for k, v := range resourceAttrsWithUnderscores { + resourceWithUnderscores.Attributes().PutStr(k, v) + } + attrsWithUnderscores := pcommon.NewMap() + attrsWithUnderscores.PutStr("_metric_private", "private metric") + attrsWithUnderscores.PutStr("metric___multi", "multi metric") + testCases := []struct { - name string - scope scope - promoteAllResourceAttributes bool - promoteResourceAttributes []string - promoteScope bool - ignoreResourceAttributes []string - ignoreAttrs []string - expectedLabels labels.Labels + name string + resource pcommon.Resource + attrs pcommon.Map + scope scope + promoteAllResourceAttributes bool + promoteResourceAttributes []string + promoteScope bool + ignoreResourceAttributes []string + ignoreAttrs []string + labelNameUnderscoreLabelSanitization bool + labelNamePreserveMultipleUnderscores bool + expectedLabels labels.Labels }{ { name: "Successful conversion without resource attribute promotion and without scope promotion", @@ -251,6 +271,121 @@ func TestCreateAttributes(t *testing.T) { "otel_scope_attr2", "value2", ), }, + // Label sanitization test cases + { + name: "Underscore sanitization enabled - prepends key_ to labels starting with single _", + resource: resourceWithUnderscores, + attrs: attrsWithUnderscores, + promoteResourceAttributes: []string{"_private"}, + labelNameUnderscoreLabelSanitization: true, + labelNamePreserveMultipleUnderscores: true, + expectedLabels: labels.FromStrings( + "__name__", "test_metric", + "instance", "service ID", + "job", "service name", + "key_private", "private value", + "key_metric_private", "private metric", + "metric___multi", "multi metric", + ), + }, + { + name: "Underscore sanitization disabled - keeps labels with _ as-is", + resource: resourceWithUnderscores, + attrs: attrsWithUnderscores, + promoteResourceAttributes: []string{"_private"}, + labelNameUnderscoreLabelSanitization: false, + labelNamePreserveMultipleUnderscores: true, + expectedLabels: labels.FromStrings( + "__name__", "test_metric", + "instance", "service ID", + "job", "service name", + "_private", "private value", + "_metric_private", "private metric", + "metric___multi", "multi metric", + ), + }, + { + name: "Multiple underscores preserved - keeps consecutive underscores", + resource: resourceWithUnderscores, + attrs: attrsWithUnderscores, + promoteResourceAttributes: []string{"label___multi"}, + labelNameUnderscoreLabelSanitization: false, + labelNamePreserveMultipleUnderscores: true, + expectedLabels: labels.FromStrings( + "__name__", "test_metric", + "instance", "service ID", + "job", "service name", + "label___multi", "multi value", + "_metric_private", "private metric", + "metric___multi", "multi metric", + ), + }, + { + name: "Multiple underscores collapsed - collapses to single underscore", + resource: resourceWithUnderscores, + attrs: attrsWithUnderscores, + promoteResourceAttributes: []string{"label___multi"}, + labelNameUnderscoreLabelSanitization: false, + labelNamePreserveMultipleUnderscores: false, + expectedLabels: labels.FromStrings( + "__name__", "test_metric", + "instance", "service ID", + "job", "service name", + "label_multi", "multi value", + "_metric_private", "private metric", + "metric_multi", "multi metric", + ), + }, + { + name: "Both sanitization options enabled", + resource: resourceWithUnderscores, + attrs: attrsWithUnderscores, + promoteResourceAttributes: []string{"_private", "label___multi"}, + labelNameUnderscoreLabelSanitization: true, + labelNamePreserveMultipleUnderscores: true, + expectedLabels: labels.FromStrings( + "__name__", "test_metric", + "instance", "service ID", + "job", "service name", + "key_private", "private value", + "label___multi", "multi value", + "key_metric_private", "private metric", + "metric___multi", "multi metric", + ), + }, + { + name: "Both sanitization options disabled", + resource: resourceWithUnderscores, + attrs: attrsWithUnderscores, + promoteResourceAttributes: []string{"_private", "label___multi"}, + labelNameUnderscoreLabelSanitization: false, + labelNamePreserveMultipleUnderscores: false, + expectedLabels: labels.FromStrings( + "__name__", "test_metric", + "instance", "service ID", + "job", "service name", + "_private", "private value", + "label_multi", "multi value", + "_metric_private", "private metric", + "metric_multi", "multi metric", + ), + }, + { + name: "Reserved labels (starting with __) are never modified", + resource: resourceWithUnderscores, + attrs: attrsWithUnderscores, + promoteResourceAttributes: []string{"__reserved__"}, + labelNameUnderscoreLabelSanitization: true, + labelNamePreserveMultipleUnderscores: false, + expectedLabels: labels.FromStrings( + "__name__", "test_metric", + "instance", "service ID", + "job", "service name", + "__reserved__", "reserved value", + "key_metric_private", "private metric", + "metric_multi", "multi metric", + ), + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -261,9 +396,24 @@ func TestCreateAttributes(t *testing.T) { PromoteResourceAttributes: tc.promoteResourceAttributes, IgnoreResourceAttributes: tc.ignoreResourceAttributes, }), - PromoteScopeMetadata: tc.promoteScope, + PromoteScopeMetadata: tc.promoteScope, + LabelNameUnderscoreSanitization: tc.labelNameUnderscoreLabelSanitization, + LabelNamePreserveMultipleUnderscores: tc.labelNamePreserveMultipleUnderscores, } - lbls, err := c.createAttributes(resource, attrs, tc.scope, settings, tc.ignoreAttrs, false, Metadata{}, model.MetricNameLabel, "test_metric") + // Use test case specific resource/attrs if provided, otherwise use defaults + // Check if tc.resource is initialized (non-zero) by trying to get its attributes + testResource := resource + testAttrs := attrs + // For pcommon types, we can check if they're non-zero by seeing if they have attributes + // Since zero-initialized Resource is not valid, we use a simple heuristic: + // if the struct has been explicitly set in the test case, use it + if tc.resource != (pcommon.Resource{}) { + testResource = tc.resource + } + if tc.attrs != (pcommon.Map{}) { + testAttrs = tc.attrs + } + lbls, err := c.createAttributes(testResource, testAttrs, tc.scope, settings, tc.ignoreAttrs, false, Metadata{}, model.MetricNameLabel, "test_metric") require.NoError(t, err) testutil.RequireEqual(t, lbls, tc.expectedLabels) diff --git a/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go b/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go index 7083ce0885..27daadc2bc 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go @@ -54,9 +54,9 @@ type Settings struct { // PromoteScopeMetadata controls whether to promote OTel scope metadata to metric labels. PromoteScopeMetadata bool EnableTypeAndUnitLabels bool - // LabelNameUnderscoreLabelSanitization controls whether to enable prepending of 'key' to labels + // LabelNameUnderscoreSanitization controls whether to enable prepending of 'key' to labels // starting with '_'. Reserved labels starting with `__` are not modified. - LabelNameUnderscoreLabelSanitization bool + LabelNameUnderscoreSanitization bool // LabelNamePreserveMultipleUnderscores enables preserving of multiple // consecutive underscores in label names when AllowUTF8 is false. LabelNamePreserveMultipleUnderscores bool @@ -310,12 +310,16 @@ func NewPromoteResourceAttributes(otlpCfg config.OTLPConfig) *PromoteResourceAtt } // addPromotedAttributes adds labels for promoted resourceAttributes to the builder. -func (s *PromoteResourceAttributes) addPromotedAttributes(builder *labels.Builder, resourceAttributes pcommon.Map, allowUTF8 bool) error { +func (s *PromoteResourceAttributes) addPromotedAttributes(builder *labels.Builder, resourceAttributes pcommon.Map, allowUTF8, underscoreSanitization, preserveMultipleUnderscores bool) error { if s == nil { return nil } - labelNamer := otlptranslator.LabelNamer{UTF8Allowed: allowUTF8} + labelNamer := otlptranslator.LabelNamer{ + UTF8Allowed: allowUTF8, + UnderscoreLabelSanitization: underscoreSanitization, + PreserveMultipleUnderscores: preserveMultipleUnderscores, + } if s.promoteAll { var err error resourceAttributes.Range(func(name string, value pcommon.Value) bool { diff --git a/storage/remote/write_handler.go b/storage/remote/write_handler.go index 266fae86a3..6bb63635b5 100644 --- a/storage/remote/write_handler.go +++ b/storage/remote/write_handler.go @@ -649,15 +649,17 @@ func (rw *rwExporter) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) er combinedAppender := otlptranslator.NewCombinedAppender(app, rw.logger, rw.ingestCTZeroSample, rw.metrics) converter := otlptranslator.NewPrometheusConverter(combinedAppender) annots, err := converter.FromMetrics(ctx, md, otlptranslator.Settings{ - AddMetricSuffixes: otlpCfg.TranslationStrategy.ShouldAddSuffixes(), - AllowUTF8: !otlpCfg.TranslationStrategy.ShouldEscape(), - PromoteResourceAttributes: otlptranslator.NewPromoteResourceAttributes(otlpCfg), - KeepIdentifyingResourceAttributes: otlpCfg.KeepIdentifyingResourceAttributes, - ConvertHistogramsToNHCB: otlpCfg.ConvertHistogramsToNHCB, - PromoteScopeMetadata: otlpCfg.PromoteScopeMetadata, - AllowDeltaTemporality: rw.allowDeltaTemporality, - LookbackDelta: rw.lookbackDelta, - EnableTypeAndUnitLabels: rw.enableTypeAndUnitLabels, + AddMetricSuffixes: otlpCfg.TranslationStrategy.ShouldAddSuffixes(), + AllowUTF8: !otlpCfg.TranslationStrategy.ShouldEscape(), + PromoteResourceAttributes: otlptranslator.NewPromoteResourceAttributes(otlpCfg), + KeepIdentifyingResourceAttributes: otlpCfg.KeepIdentifyingResourceAttributes, + ConvertHistogramsToNHCB: otlpCfg.ConvertHistogramsToNHCB, + PromoteScopeMetadata: otlpCfg.PromoteScopeMetadata, + AllowDeltaTemporality: rw.allowDeltaTemporality, + LookbackDelta: rw.lookbackDelta, + EnableTypeAndUnitLabels: rw.enableTypeAndUnitLabels, + LabelNameUnderscoreSanitization: otlpCfg.LabelNameUnderscoreSanitization, + LabelNamePreserveMultipleUnderscores: otlpCfg.LabelNamePreserveMultipleUnderscores, }) defer func() { From 3de3a296dd2c2252bb0628c19c9ef0739382521e Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Thu, 16 Oct 2025 16:08:01 +0200 Subject: [PATCH 07/14] Add reviewer feedback Signed-off-by: Arve Knudsen --- .../remote/otlptranslator/prometheusremotewrite/helper.go | 2 +- .../otlptranslator/prometheusremotewrite/metrics_to_prw.go | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/storage/remote/otlptranslator/prometheusremotewrite/helper.go b/storage/remote/otlptranslator/prometheusremotewrite/helper.go index 9f73bb1a49..a27447a90f 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/helper.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/helper.go @@ -122,7 +122,7 @@ func (c *PrometheusConverter) createAttributes(resource pcommon.Resource, attrib } } - err := settings.PromoteResourceAttributes.addPromotedAttributes(c.builder, resourceAttrs, settings.AllowUTF8, settings.LabelNameUnderscoreSanitization, settings.LabelNamePreserveMultipleUnderscores) + err := settings.PromoteResourceAttributes.addPromotedAttributes(c.builder, resourceAttrs, labelNamer) if err != nil { return labels.EmptyLabels(), err } diff --git a/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go b/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go index 27daadc2bc..94726d4edf 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go @@ -310,16 +310,11 @@ func NewPromoteResourceAttributes(otlpCfg config.OTLPConfig) *PromoteResourceAtt } // addPromotedAttributes adds labels for promoted resourceAttributes to the builder. -func (s *PromoteResourceAttributes) addPromotedAttributes(builder *labels.Builder, resourceAttributes pcommon.Map, allowUTF8, underscoreSanitization, preserveMultipleUnderscores bool) error { +func (s *PromoteResourceAttributes) addPromotedAttributes(builder *labels.Builder, resourceAttributes pcommon.Map, labelNamer otlptranslator.LabelNamer) error { if s == nil { return nil } - labelNamer := otlptranslator.LabelNamer{ - UTF8Allowed: allowUTF8, - UnderscoreLabelSanitization: underscoreSanitization, - PreserveMultipleUnderscores: preserveMultipleUnderscores, - } if s.promoteAll { var err error resourceAttributes.Range(func(name string, value pcommon.Value) bool { From f5804e7cf2542486747db98c51155f554aec5bd9 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Thu, 16 Oct 2025 16:26:41 +0200 Subject: [PATCH 08/14] Remove configuration parameters Signed-off-by: Arve Knudsen --- config/config.go | 12 +---- config/config_test.go | 46 +------------------ ..._underscore_sanitization_defaults.good.yml | 2 - ..._underscore_sanitization_disabled.good.yml | 3 -- ...l_underscore_sanitization_enabled.good.yml | 3 -- docs/configuration/configuration.md | 9 ---- storage/remote/write_handler.go | 6 ++- 7 files changed, 6 insertions(+), 75 deletions(-) delete mode 100644 config/testdata/otlp_label_underscore_sanitization_defaults.good.yml delete mode 100644 config/testdata/otlp_label_underscore_sanitization_disabled.good.yml delete mode 100644 config/testdata/otlp_label_underscore_sanitization_enabled.good.yml diff --git a/config/config.go b/config/config.go index 91b91d25fc..8e7afc1f2f 100644 --- a/config/config.go +++ b/config/config.go @@ -258,9 +258,7 @@ var ( // DefaultOTLPConfig is the default OTLP configuration. DefaultOTLPConfig = OTLPConfig{ - TranslationStrategy: otlptranslator.UnderscoreEscapingWithSuffixes, - LabelNameUnderscoreSanitization: true, - LabelNamePreserveMultipleUnderscores: true, + TranslationStrategy: otlptranslator.UnderscoreEscapingWithSuffixes, } ) @@ -1611,14 +1609,6 @@ type OTLPConfig struct { // PromoteScopeMetadata controls whether to promote OTel scope metadata (i.e. name, version, schema URL, and attributes) to metric labels. // As per OTel spec, the aforementioned scope metadata should be identifying, i.e. made into metric labels. PromoteScopeMetadata bool `yaml:"promote_scope_metadata,omitempty"` - // LabelNameUnderscoreSanitization controls whether to enable prepending of 'key_' to labels - // starting with '_'. Reserved labels starting with `__` are not modified. - // This is only relevant when AllowUTF8 is false (i.e., when using underscore escaping). - LabelNameUnderscoreSanitization bool `yaml:"label_name_underscore_sanitization,omitempty"` - // LabelNamePreserveMultipleUnderscores enables preserving of multiple consecutive underscores - // in label names when AllowUTF8 is false. When false, multiple consecutive underscores are - // collapsed to a single underscore during label name sanitization. - LabelNamePreserveMultipleUnderscores bool `yaml:"label_name_preserve_multiple_underscores,omitempty"` } // UnmarshalYAML implements the yaml.Unmarshaler interface. diff --git a/config/config_test.go b/config/config_test.go index d729d2a6aa..1f093c7959 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -175,9 +175,7 @@ var expectedConf = &Config{ PromoteResourceAttributes: []string{ "k8s.cluster.name", "k8s.job.name", "k8s.namespace.name", }, - TranslationStrategy: otlptranslator.UnderscoreEscapingWithSuffixes, - LabelNameUnderscoreSanitization: true, - LabelNamePreserveMultipleUnderscores: true, + TranslationStrategy: otlptranslator.UnderscoreEscapingWithSuffixes, }, RemoteReadConfigs: []*RemoteReadConfig{ @@ -1844,48 +1842,6 @@ func TestOTLPPromoteScopeMetadata(t *testing.T) { }) } -func TestOTLPLabelUnderscoreSanitization(t *testing.T) { - t.Run("defaults to true", func(t *testing.T) { - conf, err := LoadFile(filepath.Join("testdata", "otlp_label_underscore_sanitization_defaults.good.yml"), false, promslog.NewNopLogger()) - require.NoError(t, err) - - // Test that default values are true - require.True(t, conf.OTLPConfig.LabelNameUnderscoreSanitization) - require.True(t, conf.OTLPConfig.LabelNamePreserveMultipleUnderscores) - }) - - t.Run("explicit enabled", func(t *testing.T) { - conf, err := LoadFile(filepath.Join("testdata", "otlp_label_underscore_sanitization_enabled.good.yml"), false, promslog.NewNopLogger()) - require.NoError(t, err) - - out, err := yaml.Marshal(conf) - require.NoError(t, err) - var got Config - require.NoError(t, yaml.UnmarshalStrict(out, &got)) - - require.True(t, got.OTLPConfig.LabelNameUnderscoreSanitization) - require.True(t, got.OTLPConfig.LabelNamePreserveMultipleUnderscores) - }) - - t.Run("explicit disabled", func(t *testing.T) { - conf, err := LoadFile(filepath.Join("testdata", "otlp_label_underscore_sanitization_disabled.good.yml"), false, promslog.NewNopLogger()) - require.NoError(t, err) - - // When explicitly set to false, they should be false - require.False(t, conf.OTLPConfig.LabelNameUnderscoreSanitization) - require.False(t, conf.OTLPConfig.LabelNamePreserveMultipleUnderscores) - }) - - t.Run("empty config uses defaults", func(t *testing.T) { - conf, err := LoadFile(filepath.Join("testdata", "otlp_empty.yml"), false, promslog.NewNopLogger()) - require.NoError(t, err) - - // Empty config should use default values (true) - require.True(t, conf.OTLPConfig.LabelNameUnderscoreSanitization) - require.True(t, conf.OTLPConfig.LabelNamePreserveMultipleUnderscores) - }) -} - func TestOTLPAllowUTF8(t *testing.T) { t.Run("good config - NoUTF8EscapingWithSuffixes", func(t *testing.T) { fpath := filepath.Join("testdata", "otlp_allow_utf8.good.yml") diff --git a/config/testdata/otlp_label_underscore_sanitization_defaults.good.yml b/config/testdata/otlp_label_underscore_sanitization_defaults.good.yml deleted file mode 100644 index 3b1e9796d3..0000000000 --- a/config/testdata/otlp_label_underscore_sanitization_defaults.good.yml +++ /dev/null @@ -1,2 +0,0 @@ -otlp: - promote_resource_attributes: ["service.name"] diff --git a/config/testdata/otlp_label_underscore_sanitization_disabled.good.yml b/config/testdata/otlp_label_underscore_sanitization_disabled.good.yml deleted file mode 100644 index f8fe4ea669..0000000000 --- a/config/testdata/otlp_label_underscore_sanitization_disabled.good.yml +++ /dev/null @@ -1,3 +0,0 @@ -otlp: - label_name_underscore_sanitization: false - label_name_preserve_multiple_underscores: false diff --git a/config/testdata/otlp_label_underscore_sanitization_enabled.good.yml b/config/testdata/otlp_label_underscore_sanitization_enabled.good.yml deleted file mode 100644 index 8ce347495e..0000000000 --- a/config/testdata/otlp_label_underscore_sanitization_enabled.good.yml +++ /dev/null @@ -1,3 +0,0 @@ -otlp: - label_name_underscore_sanitization: true - label_name_preserve_multiple_underscores: true diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index 451af231c5..b3ea571b80 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -222,15 +222,6 @@ otlp: # Enables promotion of OTel scope metadata (i.e. name, version, schema URL, and attributes) to metric labels. # This is disabled by default for backwards compatibility, but according to OTel spec, scope metadata _should_ be identifying, i.e. translated to metric labels. [ promote_scope_metadata: | default = false ] - # Controls whether to enable prepending of 'key_' to labels starting with '_'. - # Reserved labels starting with '__' are not modified. - # This is only relevant when translation_strategy uses underscore escaping - # (e.g., "UnderscoreEscapingWithSuffixes" or "UnderscoreEscapingWithoutSuffixes"). - [ label_name_underscore_sanitization: | default = true ] - # Enables preserving of multiple consecutive underscores in label names when - # translation_strategy uses underscore escaping. When true (default), multiple - # consecutive underscores are preserved during label name sanitization. - [ label_name_preserve_multiple_underscores: | default = true ] # Settings related to the remote read feature. remote_read: diff --git a/storage/remote/write_handler.go b/storage/remote/write_handler.go index 6bb63635b5..8c8f71941f 100644 --- a/storage/remote/write_handler.go +++ b/storage/remote/write_handler.go @@ -658,8 +658,10 @@ func (rw *rwExporter) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) er AllowDeltaTemporality: rw.allowDeltaTemporality, LookbackDelta: rw.lookbackDelta, EnableTypeAndUnitLabels: rw.enableTypeAndUnitLabels, - LabelNameUnderscoreSanitization: otlpCfg.LabelNameUnderscoreSanitization, - LabelNamePreserveMultipleUnderscores: otlpCfg.LabelNamePreserveMultipleUnderscores, + // For backwards compatibility. + LabelNameUnderscoreSanitization: true, + // For backwards compatibility. + LabelNamePreserveMultipleUnderscores: true, }) defer func() { From 99d0967133d765220e578b91db1e966533d839e6 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Thu, 16 Oct 2025 16:56:18 +0200 Subject: [PATCH 09/14] Fix lint failure Signed-off-by: Arve Knudsen --- storage/remote/write_handler.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/storage/remote/write_handler.go b/storage/remote/write_handler.go index 8c8f71941f..9859da94c8 100644 --- a/storage/remote/write_handler.go +++ b/storage/remote/write_handler.go @@ -649,17 +649,17 @@ func (rw *rwExporter) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) er combinedAppender := otlptranslator.NewCombinedAppender(app, rw.logger, rw.ingestCTZeroSample, rw.metrics) converter := otlptranslator.NewPrometheusConverter(combinedAppender) annots, err := converter.FromMetrics(ctx, md, otlptranslator.Settings{ - AddMetricSuffixes: otlpCfg.TranslationStrategy.ShouldAddSuffixes(), - AllowUTF8: !otlpCfg.TranslationStrategy.ShouldEscape(), - PromoteResourceAttributes: otlptranslator.NewPromoteResourceAttributes(otlpCfg), - KeepIdentifyingResourceAttributes: otlpCfg.KeepIdentifyingResourceAttributes, - ConvertHistogramsToNHCB: otlpCfg.ConvertHistogramsToNHCB, - PromoteScopeMetadata: otlpCfg.PromoteScopeMetadata, - AllowDeltaTemporality: rw.allowDeltaTemporality, - LookbackDelta: rw.lookbackDelta, - EnableTypeAndUnitLabels: rw.enableTypeAndUnitLabels, + AddMetricSuffixes: otlpCfg.TranslationStrategy.ShouldAddSuffixes(), + AllowUTF8: !otlpCfg.TranslationStrategy.ShouldEscape(), + PromoteResourceAttributes: otlptranslator.NewPromoteResourceAttributes(otlpCfg), + KeepIdentifyingResourceAttributes: otlpCfg.KeepIdentifyingResourceAttributes, + ConvertHistogramsToNHCB: otlpCfg.ConvertHistogramsToNHCB, + PromoteScopeMetadata: otlpCfg.PromoteScopeMetadata, + AllowDeltaTemporality: rw.allowDeltaTemporality, + LookbackDelta: rw.lookbackDelta, + EnableTypeAndUnitLabels: rw.enableTypeAndUnitLabels, // For backwards compatibility. - LabelNameUnderscoreSanitization: true, + LabelNameUnderscoreSanitization: true, // For backwards compatibility. LabelNamePreserveMultipleUnderscores: true, }) From 7477dabcdf237f3abc41d7d780f0042f71ac4a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Krajcsovits?= Date: Thu, 16 Oct 2025 17:29:09 +0200 Subject: [PATCH 10/14] prepare bugfix release 3.7.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: György Krajcsovits --- CHANGELOG.md | 4 ++++ VERSION | 2 +- web/ui/mantine-ui/package.json | 4 ++-- web/ui/module/codemirror-promql/package.json | 4 ++-- web/ui/module/lezer-promql/package.json | 2 +- web/ui/package-lock.json | 14 +++++++------- web/ui/package.json | 2 +- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b751f298b..fe61290ca2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 3.7.1 / 2025-10-16 + +* [BUGFIX] OTLP: Prefix `key_` to label name when translating an OTel attribute name starting with a single underscore, and keep multiple consecutive underscores in label name when translating an OTel attribute name. This reverts the breaking changes introduced in 3.7.0. #17344 + ## 3.7.0 / 2025-10-15 * [CHANGE] Remote-write: the following metrics are deprecated: diff --git a/VERSION b/VERSION index 7c69a55dbb..a76ccff2a6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.7.0 +3.7.1 diff --git a/web/ui/mantine-ui/package.json b/web/ui/mantine-ui/package.json index aed3bcd593..6144afa70d 100644 --- a/web/ui/mantine-ui/package.json +++ b/web/ui/mantine-ui/package.json @@ -1,7 +1,7 @@ { "name": "@prometheus-io/mantine-ui", "private": true, - "version": "0.307.0", + "version": "0.307.1", "type": "module", "scripts": { "start": "vite", @@ -28,7 +28,7 @@ "@microsoft/fetch-event-source": "^2.0.1", "@nexucis/fuzzy": "^0.5.1", "@nexucis/kvsearch": "^0.9.1", - "@prometheus-io/codemirror-promql": "0.307.0", + "@prometheus-io/codemirror-promql": "0.307.1", "@reduxjs/toolkit": "^2.9.0", "@tabler/icons-react": "^3.35.0", "@tanstack/react-query": "^5.90.2", diff --git a/web/ui/module/codemirror-promql/package.json b/web/ui/module/codemirror-promql/package.json index 78d8a36921..3c8f6fd58c 100644 --- a/web/ui/module/codemirror-promql/package.json +++ b/web/ui/module/codemirror-promql/package.json @@ -1,6 +1,6 @@ { "name": "@prometheus-io/codemirror-promql", - "version": "0.307.0", + "version": "0.307.1", "description": "a CodeMirror mode for the PromQL language", "types": "dist/esm/index.d.ts", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ }, "homepage": "https://github.com/prometheus/prometheus/blob/main/web/ui/module/codemirror-promql/README.md", "dependencies": { - "@prometheus-io/lezer-promql": "0.307.0", + "@prometheus-io/lezer-promql": "0.307.1", "lru-cache": "^11.2.2" }, "devDependencies": { diff --git a/web/ui/module/lezer-promql/package.json b/web/ui/module/lezer-promql/package.json index 1837bc078b..951955cd53 100644 --- a/web/ui/module/lezer-promql/package.json +++ b/web/ui/module/lezer-promql/package.json @@ -1,6 +1,6 @@ { "name": "@prometheus-io/lezer-promql", - "version": "0.307.0", + "version": "0.307.1", "description": "lezer-based PromQL grammar", "main": "dist/index.cjs", "type": "module", diff --git a/web/ui/package-lock.json b/web/ui/package-lock.json index 9c39ef7c7e..6eafc4f156 100644 --- a/web/ui/package-lock.json +++ b/web/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "prometheus-io", - "version": "0.307.0", + "version": "0.307.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prometheus-io", - "version": "0.307.0", + "version": "0.307.1", "workspaces": [ "mantine-ui", "module/*" @@ -24,7 +24,7 @@ }, "mantine-ui": { "name": "@prometheus-io/mantine-ui", - "version": "0.307.0", + "version": "0.307.1", "dependencies": { "@codemirror/autocomplete": "^6.19.0", "@codemirror/language": "^6.11.3", @@ -42,7 +42,7 @@ "@microsoft/fetch-event-source": "^2.0.1", "@nexucis/fuzzy": "^0.5.1", "@nexucis/kvsearch": "^0.9.1", - "@prometheus-io/codemirror-promql": "0.307.0", + "@prometheus-io/codemirror-promql": "0.307.1", "@reduxjs/toolkit": "^2.9.0", "@tabler/icons-react": "^3.35.0", "@tanstack/react-query": "^5.90.2", @@ -87,10 +87,10 @@ }, "module/codemirror-promql": { "name": "@prometheus-io/codemirror-promql", - "version": "0.307.0", + "version": "0.307.1", "license": "Apache-2.0", "dependencies": { - "@prometheus-io/lezer-promql": "0.307.0", + "@prometheus-io/lezer-promql": "0.307.1", "lru-cache": "^11.2.2" }, "devDependencies": { @@ -120,7 +120,7 @@ }, "module/lezer-promql": { "name": "@prometheus-io/lezer-promql", - "version": "0.307.0", + "version": "0.307.1", "license": "Apache-2.0", "devDependencies": { "@lezer/generator": "^1.8.0", diff --git a/web/ui/package.json b/web/ui/package.json index b4f70b17e5..be701b3577 100644 --- a/web/ui/package.json +++ b/web/ui/package.json @@ -1,7 +1,7 @@ { "name": "prometheus-io", "description": "Monorepo for the Prometheus UI", - "version": "0.307.0", + "version": "0.307.1", "private": true, "scripts": { "build": "bash build_ui.sh --all", From 99c926b8105d45d08832974191adb603f9dbc96c Mon Sep 17 00:00:00 2001 From: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> Date: Fri, 17 Oct 2025 12:10:30 +0200 Subject: [PATCH 11/14] promql: allow 'anchored' and 'smoothed' as metric and label names Add ANCHORED and SMOOTHED keywords to the maybe_label and metric_identifier rules in the parser grammar, allowing them to be used as metric names and label names, similar to other keywords like 'offset', 'step', and 'bool'. This fixes an issue where expressions like `anchored{job="test"}` and `sum by (smoothed) (some_metric)` would fail to parse. Signed-off-by: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> --- promql/parser/generated_parser.y | 4 +- promql/parser/generated_parser.y.go | 899 ++++++++++++++-------------- promql/parser/parse_test.go | 52 ++ 3 files changed, 509 insertions(+), 446 deletions(-) diff --git a/promql/parser/generated_parser.y b/promql/parser/generated_parser.y index 3e2f13d872..d9bbb10b28 100644 --- a/promql/parser/generated_parser.y +++ b/promql/parser/generated_parser.y @@ -696,7 +696,7 @@ metric : metric_identifier label_set ; -metric_identifier: AVG | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | IDENTIFIER | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | QUANTILE | STDDEV | STDVAR | SUM | TOPK | WITHOUT | START | END | LIMITK | LIMIT_RATIO | STEP; +metric_identifier: AVG | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | IDENTIFIER | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | QUANTILE | STDDEV | STDVAR | SUM | TOPK | WITHOUT | START | END | LIMITK | LIMIT_RATIO | STEP | ANCHORED | SMOOTHED; label_set : LEFT_BRACE label_set_list RIGHT_BRACE { $$ = labels.New($2...) } @@ -953,7 +953,7 @@ counter_reset_hint : UNKNOWN_COUNTER_RESET | COUNTER_RESET | NOT_COUNTER_RESET | aggregate_op : AVG | BOTTOMK | COUNT | COUNT_VALUES | GROUP | MAX | MIN | QUANTILE | STDDEV | STDVAR | SUM | TOPK | LIMITK | LIMIT_RATIO; // Inside of grouping options label names can be recognized as keywords by the lexer. This is a list of keywords that could also be a label name. -maybe_label : AVG | BOOL | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | GROUP_LEFT | GROUP_RIGHT | IDENTIFIER | IGNORING | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | ON | QUANTILE | STDDEV | STDVAR | SUM | TOPK | START | END | ATAN2 | LIMITK | LIMIT_RATIO | STEP; +maybe_label : AVG | BOOL | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | GROUP_LEFT | GROUP_RIGHT | IDENTIFIER | IGNORING | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | ON | QUANTILE | STDDEV | STDVAR | SUM | TOPK | START | END | ATAN2 | LIMITK | LIMIT_RATIO | STEP | ANCHORED | SMOOTHED; unary_op : ADD | SUB; diff --git a/promql/parser/generated_parser.y.go b/promql/parser/generated_parser.y.go index df4611892a..eb4b32129a 100644 --- a/promql/parser/generated_parser.y.go +++ b/promql/parser/generated_parser.y.go @@ -256,337 +256,344 @@ var yyExca = [...]int16{ -1, 1, 1, -1, -2, 0, - -1, 38, - 1, 147, - 10, 147, - 24, 147, + -1, 40, + 1, 149, + 10, 149, + 24, 149, -2, 0, - -1, 68, - 2, 190, - 15, 190, - 79, 190, - 87, 190, - -2, 107, - -1, 69, - 2, 191, - 15, 191, - 79, 191, - 87, 191, - -2, 108, -1, 70, 2, 192, 15, 192, 79, 192, 87, 192, - -2, 110, + -2, 107, -1, 71, 2, 193, 15, 193, 79, 193, 87, 193, - -2, 111, + -2, 108, -1, 72, 2, 194, 15, 194, 79, 194, 87, 194, - -2, 112, + -2, 110, -1, 73, 2, 195, 15, 195, 79, 195, 87, 195, - -2, 117, + -2, 111, -1, 74, 2, 196, 15, 196, 79, 196, 87, 196, - -2, 119, + -2, 112, -1, 75, 2, 197, 15, 197, 79, 197, 87, 197, - -2, 121, + -2, 117, -1, 76, 2, 198, 15, 198, 79, 198, 87, 198, - -2, 122, + -2, 119, -1, 77, 2, 199, 15, 199, 79, 199, 87, 199, - -2, 123, + -2, 121, -1, 78, 2, 200, 15, 200, 79, 200, 87, 200, - -2, 124, + -2, 122, -1, 79, 2, 201, 15, 201, 79, 201, 87, 201, - -2, 125, + -2, 123, -1, 80, 2, 202, 15, 202, 79, 202, 87, 202, - -2, 129, + -2, 124, -1, 81, 2, 203, 15, 203, 79, 203, 87, 203, + -2, 125, + -1, 82, + 2, 204, + 15, 204, + 79, 204, + 87, 204, + -2, 129, + -1, 83, + 2, 205, + 15, 205, + 79, 205, + 87, 205, -2, 130, - -1, 133, - 41, 266, - 42, 266, - 52, 266, - 53, 266, - 57, 266, + -1, 135, + 41, 270, + 42, 270, + 52, 270, + 53, 270, + 57, 270, -2, 22, - -1, 243, - 9, 253, - 12, 253, - 13, 253, - 18, 253, - 19, 253, - 25, 253, - 41, 253, - 47, 253, - 48, 253, - 51, 253, - 57, 253, - 62, 253, - 63, 253, - 64, 253, - 65, 253, - 66, 253, - 67, 253, - 68, 253, - 69, 253, - 70, 253, - 71, 253, - 72, 253, - 73, 253, - 74, 253, - 75, 253, - 79, 253, - 83, 253, - 87, 253, - 90, 253, - 91, 253, - 92, 253, + -1, 245, + 9, 257, + 12, 257, + 13, 257, + 18, 257, + 19, 257, + 25, 257, + 41, 257, + 47, 257, + 48, 257, + 51, 257, + 57, 257, + 62, 257, + 63, 257, + 64, 257, + 65, 257, + 66, 257, + 67, 257, + 68, 257, + 69, 257, + 70, 257, + 71, 257, + 72, 257, + 73, 257, + 74, 257, + 75, 257, + 79, 257, + 83, 257, + 84, 257, + 85, 257, + 87, 257, + 90, 257, + 91, 257, + 92, 257, -2, 0, - -1, 244, - 9, 253, - 12, 253, - 13, 253, - 18, 253, - 19, 253, - 25, 253, - 41, 253, - 47, 253, - 48, 253, - 51, 253, - 57, 253, - 62, 253, - 63, 253, - 64, 253, - 65, 253, - 66, 253, - 67, 253, - 68, 253, - 69, 253, - 70, 253, - 71, 253, - 72, 253, - 73, 253, - 74, 253, - 75, 253, - 79, 253, - 83, 253, - 87, 253, - 90, 253, - 91, 253, - 92, 253, + -1, 246, + 9, 257, + 12, 257, + 13, 257, + 18, 257, + 19, 257, + 25, 257, + 41, 257, + 47, 257, + 48, 257, + 51, 257, + 57, 257, + 62, 257, + 63, 257, + 64, 257, + 65, 257, + 66, 257, + 67, 257, + 68, 257, + 69, 257, + 70, 257, + 71, 257, + 72, 257, + 73, 257, + 74, 257, + 75, 257, + 79, 257, + 83, 257, + 84, 257, + 85, 257, + 87, 257, + 90, 257, + 91, 257, + 92, 257, -2, 0, } const yyPrivate = 57344 -const yyLast = 1052 +const yyLast = 1071 var yyAct = [...]int16{ - 55, 180, 397, 395, 183, 402, 276, 235, 191, 328, - 91, 45, 342, 139, 66, 219, 89, 241, 17, 84, - 154, 242, 125, 62, 22, 184, 124, 123, 343, 409, - 410, 411, 412, 126, 120, 128, 243, 244, 64, 122, - 392, 127, 391, 362, 121, 119, 149, 319, 122, 192, - 381, 350, 360, 18, 19, 188, 59, 20, 220, 318, - 221, 131, 179, 133, 6, 187, 58, 426, 11, 12, - 14, 15, 16, 21, 23, 25, 26, 27, 28, 29, - 33, 34, 317, 316, 129, 13, 40, 189, 82, 24, - 396, 348, 214, 30, 322, 141, 31, 32, 35, 126, - 223, 360, 134, 190, 83, 369, 315, 127, 239, 323, - 222, 224, 346, 176, 178, 177, 424, 193, 197, 198, - 199, 200, 201, 202, 172, 324, 345, 175, 194, 194, - 194, 194, 194, 194, 194, 423, 173, 215, 422, 196, - 195, 195, 195, 195, 195, 195, 195, 130, 194, 132, - 203, 182, 204, 386, 237, 205, 208, 225, 188, 135, - 195, 227, 320, 2, 3, 4, 5, 268, 187, 171, - 266, 207, 385, 188, 264, 238, 59, 189, 231, 403, - 267, 229, 179, 187, 206, 260, 58, 368, 262, 265, - 189, 194, 425, 190, 269, 270, 264, 195, 311, 150, - 84, 230, 367, 195, 228, 189, 190, 194, 82, 366, - 273, 117, 120, 310, 272, 211, 128, 136, 221, 195, - 218, 190, 121, 119, 83, 217, 122, 118, 141, 271, - 36, 314, 7, 380, 178, 177, 379, 240, 216, 185, - 186, 378, 245, 246, 247, 248, 249, 250, 251, 252, - 253, 254, 255, 256, 257, 258, 259, 344, 223, 174, - 321, 145, 188, 377, 347, 148, 144, 349, 222, 224, - 340, 341, 187, 193, 376, 194, 375, 374, 194, 143, - 373, 351, 95, 10, 194, 59, 116, 195, 372, 371, - 195, 179, 413, 86, 370, 58, 195, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 53, 358, 147, 421, 146, 82, 85, 37, - 1, 170, 359, 361, 194, 363, 117, 120, 110, 67, - 115, 364, 365, 83, 117, 120, 195, 121, 119, 52, - 51, 122, 118, 178, 177, 121, 119, 382, 63, 122, - 118, 9, 9, 50, 142, 112, 114, 113, 194, 8, - 49, 153, 388, 38, 140, 390, 356, 48, 196, 47, - 195, 355, 313, 398, 399, 400, 394, 93, 46, 401, - 44, 405, 404, 407, 406, 414, 354, 279, 151, 209, - 43, 152, 389, 42, 415, 416, 194, 289, 357, 417, - 383, 41, 54, 295, 234, 419, 418, 387, 195, 325, - 278, 117, 120, 94, 420, 232, 274, 87, 408, 117, - 120, 181, 121, 119, 427, 194, 122, 118, 277, 56, - 121, 119, 291, 292, 122, 118, 293, 195, 137, 0, - 0, 0, 0, 0, 306, 0, 0, 280, 282, 284, - 285, 286, 294, 296, 299, 300, 301, 302, 303, 307, - 308, 0, 279, 281, 283, 287, 288, 290, 297, 92, - 142, 298, 289, 0, 0, 304, 305, 309, 295, 90, - 140, 0, 275, 213, 0, 278, 92, 226, 138, 59, - 0, 0, 93, 93, 0, 263, 90, 0, 0, 58, - 0, 0, 117, 120, 88, 0, 0, 291, 292, 93, - 0, 293, 0, 121, 119, 0, 0, 122, 118, 306, - 0, 82, 280, 282, 284, 285, 286, 294, 296, 299, - 300, 301, 302, 303, 307, 308, 0, 83, 281, 283, - 287, 288, 290, 297, 0, 0, 298, 178, 177, 0, - 304, 305, 309, 59, 0, 116, 57, 84, 0, 60, - 0, 0, 22, 58, 117, 120, 210, 0, 0, 61, - 0, 0, 261, 0, 0, 121, 119, 0, 0, 122, - 118, 0, 96, 98, 0, 82, 0, 0, 0, 0, - 0, 18, 19, 107, 108, 20, 0, 110, 111, 115, - 97, 83, 0, 0, 0, 0, 68, 69, 70, 71, + 57, 182, 401, 399, 185, 406, 278, 237, 193, 332, + 93, 47, 346, 141, 68, 221, 91, 413, 414, 415, + 416, 127, 128, 64, 156, 186, 66, 126, 347, 326, + 129, 243, 122, 125, 130, 244, 245, 246, 119, 122, + 118, 124, 123, 121, 327, 151, 124, 118, 214, 123, + 121, 396, 373, 124, 120, 364, 395, 366, 323, 385, + 328, 354, 352, 133, 216, 135, 6, 98, 100, 101, + 364, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 324, 112, 113, 117, 99, 42, 131, 315, 112, + 144, 117, 136, 400, 241, 350, 191, 143, 128, 349, + 142, 137, 270, 314, 322, 320, 129, 268, 317, 114, + 116, 115, 192, 95, 233, 178, 114, 116, 115, 195, + 199, 200, 201, 202, 203, 204, 174, 321, 319, 177, + 196, 196, 196, 196, 196, 196, 196, 232, 175, 217, + 267, 130, 197, 197, 197, 197, 197, 197, 197, 132, + 196, 134, 138, 205, 390, 407, 239, 207, 210, 227, + 206, 223, 197, 229, 428, 2, 3, 4, 5, 360, + 190, 194, 429, 389, 359, 7, 266, 240, 61, 86, + 189, 231, 269, 427, 181, 150, 426, 262, 60, 358, + 264, 119, 122, 196, 425, 209, 271, 272, 266, 197, + 152, 225, 123, 121, 230, 197, 124, 120, 208, 196, + 84, 224, 226, 119, 122, 38, 384, 213, 222, 383, + 223, 197, 10, 382, 123, 121, 85, 235, 124, 120, + 143, 190, 88, 318, 238, 381, 180, 179, 241, 242, + 380, 189, 379, 378, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 348, + 225, 198, 325, 191, 94, 377, 351, 376, 97, 353, + 224, 226, 344, 345, 92, 195, 375, 196, 374, 192, + 196, 39, 228, 355, 61, 55, 196, 95, 1, 197, + 181, 87, 197, 149, 60, 148, 172, 69, 197, 54, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 417, 84, 362, 65, 53, + 190, 9, 9, 144, 52, 51, 363, 365, 196, 367, + 189, 155, 85, 142, 275, 368, 369, 184, 274, 50, + 197, 140, 180, 179, 190, 49, 95, 48, 372, 119, + 122, 386, 191, 273, 189, 8, 46, 153, 211, 40, + 123, 121, 196, 371, 124, 120, 392, 198, 192, 394, + 370, 388, 94, 45, 197, 154, 191, 402, 403, 404, + 398, 44, 92, 405, 43, 409, 408, 411, 410, 418, + 90, 281, 192, 56, 236, 95, 422, 316, 419, 420, + 196, 291, 361, 421, 393, 119, 122, 297, 329, 423, + 96, 391, 197, 234, 280, 276, 123, 121, 424, 89, + 124, 120, 412, 119, 122, 187, 188, 183, 431, 196, + 279, 119, 122, 58, 123, 121, 293, 294, 124, 120, + 295, 197, 123, 121, 139, 0, 124, 120, 308, 0, + 0, 282, 284, 286, 287, 288, 296, 298, 301, 302, + 303, 304, 305, 309, 310, 0, 281, 283, 285, 289, + 290, 292, 299, 313, 312, 300, 291, 0, 220, 306, + 307, 311, 297, 219, 0, 0, 277, 387, 0, 280, + 147, 0, 190, 61, 0, 146, 218, 0, 0, 265, + 0, 0, 189, 60, 430, 0, 119, 122, 145, 0, + 0, 293, 294, 0, 0, 295, 0, 123, 121, 0, + 0, 124, 120, 308, 191, 84, 282, 284, 286, 287, + 288, 296, 298, 301, 302, 303, 304, 305, 309, 310, + 192, 85, 283, 285, 289, 290, 292, 299, 313, 312, + 300, 180, 179, 0, 306, 307, 311, 61, 0, 118, + 59, 86, 0, 62, 0, 0, 22, 60, 0, 0, + 212, 0, 0, 63, 0, 0, 263, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 98, 100, 0, 84, + 0, 0, 0, 0, 0, 18, 19, 109, 110, 20, + 0, 112, 113, 117, 99, 85, 0, 0, 0, 0, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 0, 0, 0, 13, 114, 116, + 115, 24, 37, 36, 215, 30, 0, 0, 31, 32, + 67, 61, 41, 0, 59, 86, 0, 62, 0, 0, + 22, 60, 0, 119, 122, 0, 0, 63, 0, 0, + 0, 0, 0, 0, 123, 121, 0, 0, 124, 120, + 0, 357, 0, 84, 0, 0, 0, 0, 61, 18, + 19, 0, 0, 20, 181, 0, 0, 0, 60, 85, + 356, 0, 0, 0, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 0, 0, + 84, 13, 0, 0, 0, 24, 37, 36, 0, 30, + 0, 0, 31, 32, 67, 61, 85, 0, 59, 86, + 0, 62, 331, 0, 22, 60, 180, 179, 0, 330, + 0, 63, 0, 334, 335, 333, 340, 342, 339, 341, + 336, 337, 338, 343, 0, 0, 0, 84, 0, 0, + 0, 198, 0, 18, 19, 0, 0, 20, 0, 0, + 0, 0, 0, 85, 0, 0, 0, 0, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 0, 0, 0, 13, 112, 114, 113, 24, 0, 0, - 0, 30, 0, 0, 31, 32, 65, 59, 39, 0, - 57, 84, 0, 60, 0, 0, 22, 58, 0, 0, - 0, 0, 233, 61, 0, 0, 188, 0, 0, 236, - 0, 0, 0, 239, 0, 0, 187, 353, 0, 82, - 0, 0, 0, 0, 59, 18, 19, 0, 0, 20, - 179, 0, 0, 0, 58, 83, 352, 0, 189, 0, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 190, 384, 82, 13, 0, 0, - 0, 24, 0, 0, 0, 30, 0, 0, 31, 32, - 65, 59, 83, 0, 57, 84, 0, 60, 0, 0, - 22, 58, 178, 177, 0, 0, 0, 61, 0, 117, - 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 121, 119, 0, 82, 122, 118, 0, 196, 0, 18, - 19, 17, 36, 20, 0, 0, 0, 22, 0, 83, - 0, 0, 0, 0, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 0, 0, - 0, 13, 0, 0, 0, 24, 18, 19, 0, 30, - 20, 0, 31, 32, 65, 0, 0, 0, 0, 0, - 0, 11, 12, 14, 15, 16, 21, 23, 25, 26, - 27, 28, 29, 33, 34, 116, 0, 0, 13, 0, - 0, 0, 24, 212, 0, 0, 30, 0, 0, 31, - 32, 35, 0, 0, 116, 0, 0, 0, 0, 0, - 0, 0, 96, 98, 99, 0, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 0, 110, 111, 115, - 97, 96, 98, 99, 0, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 0, 110, 111, 115, 97, - 116, 0, 0, 0, 112, 114, 113, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, - 0, 0, 0, 112, 114, 113, 0, 96, 98, 99, - 0, 100, 101, 102, 0, 104, 105, 106, 107, 108, - 109, 0, 110, 111, 115, 97, 96, 98, 99, 0, - 100, 101, 0, 116, 104, 105, 0, 107, 108, 109, - 0, 110, 111, 115, 97, 312, 0, 0, 0, 112, - 114, 113, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 98, 0, 0, 0, 0, 0, 0, 112, 114, - 113, 107, 108, 0, 0, 110, 0, 115, 97, 117, - 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 121, 119, 0, 0, 122, 118, 0, 0, 327, 0, - 0, 0, 112, 114, 113, 326, 0, 0, 0, 330, - 331, 329, 336, 338, 335, 337, 332, 333, 334, 339, - 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 330, 331, 329, 336, 338, 335, 337, 332, 333, - 334, 339, + 82, 83, 17, 86, 0, 13, 0, 0, 22, 24, + 37, 36, 397, 30, 0, 0, 31, 32, 67, 0, + 0, 0, 0, 334, 335, 333, 340, 342, 339, 341, + 336, 337, 338, 343, 0, 0, 0, 18, 19, 0, + 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 11, 12, 14, 15, 16, 21, 23, 25, + 26, 27, 28, 29, 33, 34, 17, 38, 0, 13, + 0, 0, 22, 24, 37, 36, 0, 30, 0, 0, + 31, 32, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 18, 19, 0, 0, 20, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 11, 12, 14, 15, + 16, 21, 23, 25, 26, 27, 28, 29, 33, 34, + 118, 0, 0, 13, 0, 0, 0, 24, 37, 36, + 0, 30, 0, 0, 31, 32, 35, 0, 0, 118, + 0, 0, 0, 0, 0, 0, 0, 98, 100, 101, + 0, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 0, 112, 113, 117, 99, 98, 100, 101, 0, + 102, 103, 104, 0, 106, 107, 108, 109, 110, 111, + 173, 112, 113, 117, 99, 118, 0, 61, 0, 114, + 116, 115, 0, 181, 118, 0, 0, 60, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 114, 116, + 115, 0, 98, 100, 101, 0, 102, 103, 0, 84, + 106, 107, 100, 109, 110, 111, 0, 112, 113, 117, + 99, 0, 109, 110, 0, 85, 112, 0, 117, 99, + 0, 0, 0, 0, 0, 180, 179, 0, 0, 0, + 0, 0, 0, 0, 114, 116, 115, 0, 0, 0, + 0, 0, 0, 114, 116, 115, 0, 0, 0, 0, + 176, } var yyPact = [...]int16{ - 62, 222, 749, 749, 628, 6, -1000, -1000, -1000, 217, + 64, 165, 844, 844, 632, 780, -1000, -1000, -1000, 202, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 484, -1000, 280, -1000, - 830, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 523, 20, 201, -1000, -1000, - 712, -1000, 712, 187, -1000, 144, 202, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 370, -1000, + 266, -1000, 906, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -3, 19, 126, + -1000, -1000, 716, -1000, 716, 166, -1000, 86, 137, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 468, -1000, -1000, 259, -1000, -1000, - 312, 261, -1000, -1000, 22, -1000, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, 167, -1000, -1000, 149, 47, 276, 276, 276, - 276, 276, 276, 201, -46, -1000, 169, 169, 544, -1000, - 811, 461, 272, -17, -1000, 70, 276, 218, -1000, -1000, - 56, 214, -1000, -1000, 467, -1000, 179, -1000, 176, 647, - 712, -1000, -65, -44, -1000, 712, 712, 712, 712, 712, - 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, - -1000, -1000, -1000, 480, 174, 155, 523, -1000, -1000, 276, - -1000, 152, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 253, - 253, 208, -1000, 523, -1000, 276, 144, -8, -8, -17, - -17, -17, -17, -1000, -1000, -1000, 460, -1000, -1000, 191, - -1000, 830, -1000, -1000, -1000, 948, -1000, 352, -1000, 81, - -1000, -1000, -1000, -1000, -1000, 57, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 21, 136, 68, -1000, -1000, -1000, 991, - 929, 169, 169, 169, 169, 272, 272, 541, 541, 541, - 895, 876, 541, 541, 895, 272, 272, 541, 272, 929, - -1000, 111, 97, 276, -17, 69, 276, 461, 29, -1000, - -1000, -1000, 665, -1000, 364, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 321, -1000, -1000, 488, + -1000, -1000, 291, 181, -1000, -1000, 21, -1000, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, 978, -1000, -1000, 335, 169, 275, + 275, 275, 275, 275, 275, 126, -57, -1000, 193, 193, + 548, -1000, 26, 612, 33, -15, -1000, 42, 275, 476, + -1000, -1000, 216, 157, -1000, -1000, 262, -1000, 179, -1000, + 112, 222, 716, -1000, -51, -44, -1000, 716, 716, 716, + 716, 716, 716, 716, 716, 716, 716, 716, 716, 716, + 716, 716, -1000, -1000, -1000, 484, 125, 92, -3, -1000, + -1000, 275, -1000, 87, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 161, 161, 332, -1000, -3, -1000, 275, 86, -10, + -10, -15, -15, -15, -15, -1000, -1000, -1000, 464, -1000, + -1000, 81, -1000, 906, -1000, -1000, -1000, 390, -1000, 88, + -1000, 103, -1000, -1000, -1000, -1000, -1000, 102, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 32, 55, 3, -1000, -1000, + -1000, 715, 980, 193, 193, 193, 193, 33, 33, 545, + 545, 545, 971, 925, 545, 545, 971, 33, 33, 545, + 33, 980, -1000, 84, 80, 275, -15, 40, 275, 612, + 39, -1000, -1000, -1000, 669, -1000, 167, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 712, 276, -1000, -1000, -1000, -1000, -1000, -1000, 82, - 82, 17, 82, 92, 92, 185, 88, -1000, -1000, 288, - 283, 282, 274, 271, 270, 268, 257, 235, 230, 227, - -1000, -1000, -1000, -1000, -1000, 28, 276, 378, -1000, 698, - -1000, 151, -1000, -1000, -1000, 385, -1000, 830, 370, -1000, - -1000, -1000, 82, -1000, 16, 14, 1013, -1000, -1000, -1000, - 33, 164, 164, 164, 253, 165, 165, 33, 165, 33, - -66, -1000, 285, -1000, 276, -1000, -1000, -1000, -1000, -1000, - -1000, 82, 82, -1000, -1000, -1000, 82, -1000, -1000, -1000, - -1000, -1000, -1000, 164, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 276, 293, -1000, -1000, -1000, 114, -1000, - 170, -1000, 46, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 716, 275, -1000, -1000, -1000, + -1000, -1000, -1000, 51, 51, 31, 51, 78, 78, 346, + 35, -1000, -1000, 272, 270, 261, 259, 237, 236, 234, + 229, 217, 213, 210, -1000, -1000, -1000, -1000, -1000, 37, + 275, 465, -1000, 364, -1000, 152, -1000, -1000, -1000, 389, + -1000, 906, 382, -1000, -1000, -1000, 51, -1000, 30, 25, + 785, -1000, -1000, -1000, 36, 311, 311, 311, 161, 141, + 141, 36, 141, 36, -78, -1000, 308, -1000, 275, -1000, + -1000, -1000, -1000, -1000, -1000, 51, 51, -1000, -1000, -1000, + 51, -1000, -1000, -1000, -1000, -1000, -1000, 311, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 275, 172, -1000, + -1000, -1000, 162, -1000, 150, -1000, 483, -1000, -1000, -1000, + -1000, -1000, } var yyPgo = [...]int16{ - 0, 438, 13, 429, 6, 15, 428, 348, 23, 421, - 10, 418, 14, 283, 359, 417, 16, 416, 28, 12, - 415, 413, 7, 409, 9, 5, 406, 3, 2, 4, - 404, 25, 1, 402, 401, 27, 199, 393, 391, 86, - 390, 389, 26, 388, 38, 380, 11, 378, 369, 367, - 361, 360, 353, 340, 339, 312, 0, 329, 8, 321, - 320, 319, + 0, 444, 13, 433, 6, 15, 430, 318, 23, 427, + 10, 422, 14, 222, 355, 419, 16, 415, 28, 12, + 413, 410, 7, 408, 9, 5, 396, 3, 2, 4, + 394, 25, 1, 393, 384, 33, 200, 381, 375, 86, + 373, 358, 27, 357, 26, 356, 11, 347, 345, 339, + 331, 325, 324, 319, 299, 285, 0, 297, 8, 296, + 288, 281, } var yyR1 = [...]int8{ @@ -603,21 +610,22 @@ var yyR1 = [...]int8{ 2, 2, 2, 2, 2, 14, 14, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 13, 13, 13, 13, 15, 15, 15, 16, - 16, 16, 16, 16, 16, 16, 61, 21, 21, 21, - 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 30, 30, 30, 22, 22, 22, 22, 23, 23, 23, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 25, 25, 26, 26, 26, 11, 11, 11, 11, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 13, 13, 13, 13, 15, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 61, 21, + 21, 21, 21, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 30, 30, 30, 22, 22, 22, 22, 23, + 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 25, 25, 26, 26, 26, 11, 11, + 11, 11, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 8, 8, 5, 5, 5, 5, - 46, 46, 29, 29, 31, 31, 32, 32, 28, 27, - 27, 52, 10, 19, 19, 59, 59, 59, 59, 59, - 59, 59, 59, 12, 12, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 57, + 6, 6, 6, 6, 6, 6, 6, 6, 8, 8, + 5, 5, 5, 5, 46, 46, 29, 29, 31, 31, + 32, 32, 28, 27, 27, 52, 10, 19, 19, 59, + 59, 59, 59, 59, 59, 59, 59, 12, 12, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 57, } var yyR2 = [...]int8{ @@ -634,113 +642,116 @@ var yyR2 = [...]int8{ 1, 3, 3, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 3, 4, 2, 0, 3, 1, 2, 3, - 3, 1, 3, 3, 2, 1, 2, 0, 3, 2, - 1, 1, 3, 1, 3, 4, 1, 3, 5, 5, - 1, 1, 1, 4, 3, 3, 2, 3, 1, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 4, 3, 3, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 4, 2, 0, 3, 1, + 2, 3, 3, 1, 3, 3, 2, 1, 2, 0, + 3, 2, 1, 1, 3, 1, 3, 4, 1, 3, + 5, 5, 1, 1, 1, 4, 3, 3, 2, 3, + 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 4, 3, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, - 1, 1, 1, 0, 1, 1, 2, 3, 4, 6, - 7, 4, 1, 1, 1, 1, 2, 3, 3, 3, - 3, 3, 3, 3, 6, 1, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 1, 1, 1, 2, 1, 1, 1, 0, 1, 1, + 2, 3, 4, 6, 7, 4, 1, 1, 1, 1, + 2, 3, 3, 3, 3, 3, 3, 3, 6, 1, + 3, } var yyChk = [...]int16{ -1000, -60, 101, 102, 103, 104, 2, 10, -14, -7, -13, 62, 63, 79, 64, 65, 66, 12, 47, 48, 51, 67, 18, 68, 83, 69, 70, 71, 72, 73, - 87, 90, 91, 74, 75, 92, 13, -61, -14, 10, - -39, -34, -37, -40, -45, -46, -47, -48, -49, -51, - -52, -53, -54, -55, -33, -56, -3, 12, 19, 9, - 15, 25, -8, -7, -44, 92, -12, -57, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 41, 57, 13, -55, -13, -15, 20, -16, - 12, -10, 2, 25, -21, 2, 41, 59, 42, 43, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 56, 57, 83, 85, 84, 58, 14, 41, 57, 53, - 42, 52, 56, -35, -42, 2, 79, 87, 15, -42, - -39, -56, -39, -56, -44, 15, 15, -1, 20, -2, - 12, -10, 2, 20, 7, 2, 4, 2, 4, 24, - -36, -43, -38, -50, 78, -36, -36, -36, -36, -36, + 87, 90, 91, 74, 75, 92, 85, 84, 13, -61, + -14, 10, -39, -34, -37, -40, -45, -46, -47, -48, + -49, -51, -52, -53, -54, -55, -33, -56, -3, 12, + 19, 9, 15, 25, -8, -7, -44, 92, -12, -57, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 41, 57, 13, -55, -13, -15, + 20, -16, 12, -10, 2, 25, -21, 2, 41, 59, + 42, 43, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 56, 57, 83, 85, 84, 58, 14, 41, + 57, 53, 42, 52, 56, -35, -42, 2, 79, 87, + 15, -42, -39, -56, -39, -56, -44, 15, 15, -1, + 20, -2, 12, -10, 2, 20, 7, 2, 4, 2, + 4, 24, -36, -43, -38, -50, 78, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -59, 2, -46, -8, 92, -12, -56, 68, 67, 15, - -32, -9, 2, -29, -31, 90, 91, 19, 9, 41, - 57, -58, 2, -56, -46, -8, 92, -56, -56, -56, - -56, -56, -56, -42, -35, -18, 15, 2, -18, -41, - 22, -39, 22, 22, 22, -56, 20, 7, 2, -5, - 2, 4, 54, 44, 55, -5, 20, -16, 25, 2, - 25, 2, -20, 5, -30, -22, 12, -29, -31, 16, - -39, 82, 86, 80, 81, -39, -39, -39, -39, -39, + -36, -36, -59, 2, -46, -8, 92, -12, -56, 68, + 67, 15, -32, -9, 2, -29, -31, 90, 91, 19, + 9, 41, 57, -58, 2, -56, -46, -8, 92, -56, + -56, -56, -56, -56, -56, -42, -35, -18, 15, 2, + -18, -41, 22, -39, 22, 22, 22, -56, 20, 7, + 2, -5, 2, 4, 54, 44, 55, -5, 20, -16, + 25, 2, 25, 2, -20, 5, -30, -22, 12, -29, + -31, 16, -39, 82, 86, 80, 81, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -46, 92, -12, 15, -56, 15, 15, -56, 15, -29, - -29, 21, 6, 2, -17, 22, -4, -6, 25, 2, - 62, 78, 63, 79, 64, 65, 66, 80, 81, 12, - 82, 47, 48, 51, 67, 18, 68, 83, 86, 69, - 70, 71, 72, 73, 90, 91, 59, 74, 75, 92, - 22, 7, 7, 20, -2, 25, 2, 25, 2, 26, - 26, -31, 26, 41, 57, -23, 24, 17, -24, 30, - 28, 29, 35, 36, 37, 33, 31, 34, 32, 38, - -18, -18, -19, -18, -19, 15, 15, -56, 22, -56, - 22, -58, 21, 2, 22, 7, 2, -39, -56, -28, - 19, -28, 26, -28, -22, -22, 24, 17, 2, 17, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 22, -56, 22, 7, 21, 2, 22, -4, 22, - -28, 26, 26, 17, -24, -27, 57, -28, -32, -32, - -32, -29, -25, 14, -25, -27, -25, -27, -11, 95, - 96, 97, 98, 7, -56, -28, -28, -28, -26, -32, - -56, 22, 24, 21, 2, 22, 21, -32, + -39, -39, -46, 92, -12, 15, -56, 15, 15, -56, + 15, -29, -29, 21, 6, 2, -17, 22, -4, -6, + 25, 2, 62, 78, 63, 79, 64, 65, 66, 80, + 81, 12, 82, 47, 48, 51, 67, 18, 68, 83, + 86, 69, 70, 71, 72, 73, 90, 91, 59, 74, + 75, 92, 85, 84, 22, 7, 7, 20, -2, 25, + 2, 25, 2, 26, 26, -31, 26, 41, 57, -23, + 24, 17, -24, 30, 28, 29, 35, 36, 37, 33, + 31, 34, 32, 38, -18, -18, -19, -18, -19, 15, + 15, -56, 22, -56, 22, -58, 21, 2, 22, 7, + 2, -39, -56, -28, 19, -28, 26, -28, -22, -22, + 24, 17, 2, 17, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 22, -56, 22, 7, 21, + 2, 22, -4, 22, -28, 26, 26, 17, -24, -27, + 57, -28, -32, -32, -32, -29, -25, 14, -25, -27, + -25, -27, -11, 95, 96, 97, 98, 7, -56, -28, + -28, -28, -26, -32, -56, 22, 24, 21, 2, 22, + 21, -32, } var yyDef = [...]int16{ - 0, -2, 135, 135, 0, 0, 7, 6, 1, 135, + 0, -2, 137, 137, 0, 0, 7, 6, 1, 137, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 0, 2, -2, 3, - 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 0, 113, 240, 241, - 0, 251, 0, 90, 91, 131, 0, 275, -2, -2, + 126, 127, 128, 129, 130, 131, 132, 133, 0, 2, + -2, 3, 4, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 0, 113, + 244, 245, 0, 255, 0, 90, 91, 131, 0, 279, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, 234, 235, 0, 5, 105, 0, 134, 137, - 0, 141, 145, 252, 146, 150, 46, 46, 46, 46, + -2, -2, -2, -2, 238, 239, 0, 5, 105, 0, + 136, 139, 0, 143, 147, 256, 148, 152, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 0, 74, 75, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 25, 26, 0, 0, 0, 64, - 0, 22, 88, -2, 89, 0, 0, 0, 94, 96, - 0, 100, 104, 132, 0, 138, 0, 144, 0, 149, - 0, 45, 50, 51, 47, 0, 0, 0, 0, 0, + 46, 46, 46, 46, 0, 74, 75, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 25, 26, 0, 0, + 0, 64, 0, 22, 88, -2, 89, 0, 0, 0, + 94, 96, 0, 100, 104, 134, 0, 140, 0, 146, + 0, 151, 0, 45, 50, 51, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 72, 73, 255, 0, 0, 0, 262, 263, 264, 0, - 76, 0, 78, 246, 247, 79, 80, 242, 243, 0, - 0, 0, 87, 71, 265, 0, 0, 267, 268, 269, - 270, 271, 272, 23, 24, 27, 0, 57, 28, 0, - 66, 68, 70, 276, 273, 0, 92, 0, 97, 0, - 103, 236, 237, 238, 239, 0, 133, 136, 139, 142, - 140, 143, 148, 151, 153, 156, 160, 161, 162, 0, - 29, 0, 0, -2, -2, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 256, 0, 0, 0, 266, 0, 0, 0, 0, 244, - 245, 81, 0, 86, 0, 56, 59, 61, 62, 63, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 0, 0, 72, 73, 259, 0, 0, 0, 266, 267, + 268, 0, 76, 0, 78, 250, 251, 79, 80, 246, + 247, 0, 0, 0, 87, 71, 269, 0, 0, 271, + 272, 273, 274, 275, 276, 23, 24, 27, 0, 57, + 28, 0, 66, 68, 70, 280, 277, 0, 92, 0, + 97, 0, 103, 240, 241, 242, 243, 0, 135, 138, + 141, 144, 142, 145, 150, 153, 155, 158, 162, 163, + 164, 0, 29, 0, 0, -2, -2, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 260, 0, 0, 0, 270, 0, 0, 0, + 0, 248, 249, 81, 0, 86, 0, 56, 59, 61, + 62, 63, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, - 65, 69, 0, 93, 95, 98, 102, 99, 101, 0, - 0, 0, 0, 0, 0, 0, 0, 166, 168, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 48, 49, 52, 254, 53, 0, 0, 0, 257, 0, - 77, 0, 83, 85, 54, 0, 60, 67, 0, 152, - 248, 154, 0, 157, 0, 0, 0, 164, 169, 165, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 258, 0, 261, 0, 82, 84, 55, 58, 274, - 155, 0, 0, 163, 167, 170, 0, 250, 171, 172, - 173, 174, 175, 0, 176, 177, 178, 179, 180, 186, - 187, 188, 189, 0, 0, 158, 159, 249, 0, 184, - 0, 259, 0, 182, 185, 260, 181, 183, + 234, 235, 236, 237, 65, 69, 0, 93, 95, 98, + 102, 99, 101, 0, 0, 0, 0, 0, 0, 0, + 0, 168, 170, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 48, 49, 52, 258, 53, 0, + 0, 0, 261, 0, 77, 0, 83, 85, 54, 0, + 60, 67, 0, 154, 252, 156, 0, 159, 0, 0, + 0, 166, 171, 167, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 262, 0, 265, 0, 82, + 84, 55, 58, 278, 157, 0, 0, 165, 169, 172, + 0, 254, 173, 174, 175, 176, 177, 0, 178, 179, + 180, 181, 182, 188, 189, 190, 191, 0, 0, 160, + 161, 253, 0, 186, 0, 263, 0, 184, 187, 264, + 183, 185, } var yyTok1 = [...]int8{ @@ -1680,82 +1691,82 @@ yydefault: { yyVAL.labels = yyDollar[1].labels } - case 132: + case 134: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.labels = labels.New(yyDollar[2].lblList...) } - case 133: + case 135: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.labels = labels.New(yyDollar[2].lblList...) } - case 134: + case 136: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.labels = labels.New() } - case 135: + case 137: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.labels = labels.New() } - case 136: + case 138: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.lblList = append(yyDollar[1].lblList, yyDollar[3].label) } - case 137: + case 139: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.lblList = []labels.Label{yyDollar[1].label} } - case 138: + case 140: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label set", "\",\" or \"}\"") yyVAL.lblList = yyDollar[1].lblList } - case 139: - yyDollar = yyS[yypt-3 : yypt+1] - { - yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} - } - case 140: - yyDollar = yyS[yypt-3 : yypt+1] - { - yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} - } case 141: - yyDollar = yyS[yypt-1 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] { - yyVAL.label = labels.Label{Name: labels.MetricName, Value: yyDollar[1].item.Val} + yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} } case 142: yyDollar = yyS[yypt-3 : yypt+1] { - yylex.(*parser).unexpected("label set", "string") - yyVAL.label = labels.Label{} + yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} } case 143: + yyDollar = yyS[yypt-1 : yypt+1] + { + yyVAL.label = labels.Label{Name: labels.MetricName, Value: yyDollar[1].item.Val} + } + case 144: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("label set", "string") yyVAL.label = labels.Label{} } - case 144: + case 145: + yyDollar = yyS[yypt-3 : yypt+1] + { + yylex.(*parser).unexpected("label set", "string") + yyVAL.label = labels.Label{} + } + case 146: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label set", "\"=\"") yyVAL.label = labels.Label{} } - case 145: + case 147: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("label set", "identifier or \"}\"") yyVAL.label = labels.Label{} } - case 146: + case 148: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).generatedParserResult = &seriesDescription{ @@ -1763,33 +1774,33 @@ yydefault: values: yyDollar[2].series, } } - case 147: + case 149: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.series = []SequenceValue{} } - case 148: + case 150: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = append(yyDollar[1].series, yyDollar[3].series...) } - case 149: + case 151: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.series = yyDollar[1].series } - case 150: + case 152: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("series values", "") yyVAL.series = nil } - case 151: + case 153: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.series = []SequenceValue{{Omitted: true}} } - case 152: + case 154: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1797,12 +1808,12 @@ yydefault: yyVAL.series = append(yyVAL.series, SequenceValue{Omitted: true}) } } - case 153: + case 155: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.series = []SequenceValue{{Value: yyDollar[1].float}} } - case 154: + case 156: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1811,7 +1822,7 @@ yydefault: yyVAL.series = append(yyVAL.series, SequenceValue{Value: yyDollar[1].float}) } } - case 155: + case 157: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1821,12 +1832,12 @@ yydefault: yyDollar[1].float += yyDollar[2].float } } - case 156: + case 158: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.series = []SequenceValue{{Histogram: yyDollar[1].histogram}} } - case 157: + case 159: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1836,7 +1847,7 @@ yydefault: //$1 += $2 } } - case 158: + case 160: yyDollar = yyS[yypt-5 : yypt+1] { val, err := yylex.(*parser).histogramsIncreaseSeries(yyDollar[1].histogram, yyDollar[3].histogram, yyDollar[5].uint) @@ -1845,7 +1856,7 @@ yydefault: } yyVAL.series = val } - case 159: + case 161: yyDollar = yyS[yypt-5 : yypt+1] { val, err := yylex.(*parser).histogramsDecreaseSeries(yyDollar[1].histogram, yyDollar[3].histogram, yyDollar[5].uint) @@ -1854,7 +1865,7 @@ yydefault: } yyVAL.series = val } - case 160: + case 162: yyDollar = yyS[yypt-1 : yypt+1] { if yyDollar[1].item.Val != "stale" { @@ -1862,130 +1873,130 @@ yydefault: } yyVAL.float = math.Float64frombits(value.StaleNaN) } - case 163: + case 165: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&yyDollar[2].descriptors) } - case 164: + case 166: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&yyDollar[2].descriptors) } - case 165: + case 167: yyDollar = yyS[yypt-3 : yypt+1] { m := yylex.(*parser).newMap() yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&m) } - case 166: + case 168: yyDollar = yyS[yypt-2 : yypt+1] { m := yylex.(*parser).newMap() yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&m) } - case 167: + case 169: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = *(yylex.(*parser).mergeMaps(&yyDollar[1].descriptors, &yyDollar[3].descriptors)) } - case 168: + case 170: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.descriptors = yyDollar[1].descriptors } - case 169: + case 171: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("histogram description", "histogram description key, e.g. buckets:[5 10 7]") } - case 170: - yyDollar = yyS[yypt-3 : yypt+1] - { - yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["schema"] = yyDollar[3].int - } - case 171: - yyDollar = yyS[yypt-3 : yypt+1] - { - yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["sum"] = yyDollar[3].float - } case 172: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["count"] = yyDollar[3].float + yyVAL.descriptors["schema"] = yyDollar[3].int } case 173: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["z_bucket"] = yyDollar[3].float + yyVAL.descriptors["sum"] = yyDollar[3].float } case 174: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["z_bucket_w"] = yyDollar[3].float + yyVAL.descriptors["count"] = yyDollar[3].float } case 175: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["custom_values"] = yyDollar[3].bucket_set + yyVAL.descriptors["z_bucket"] = yyDollar[3].float } case 176: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["buckets"] = yyDollar[3].bucket_set + yyVAL.descriptors["z_bucket_w"] = yyDollar[3].float } case 177: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["offset"] = yyDollar[3].int + yyVAL.descriptors["custom_values"] = yyDollar[3].bucket_set } case 178: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["n_buckets"] = yyDollar[3].bucket_set + yyVAL.descriptors["buckets"] = yyDollar[3].bucket_set } case 179: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["n_offset"] = yyDollar[3].int + yyVAL.descriptors["offset"] = yyDollar[3].int } case 180: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["counter_reset_hint"] = yyDollar[3].item + yyVAL.descriptors["n_buckets"] = yyDollar[3].bucket_set } case 181: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] { - yyVAL.bucket_set = yyDollar[2].bucket_set + yyVAL.descriptors = yylex.(*parser).newMap() + yyVAL.descriptors["n_offset"] = yyDollar[3].int } case 182: yyDollar = yyS[yypt-3 : yypt+1] { - yyVAL.bucket_set = yyDollar[2].bucket_set + yyVAL.descriptors = yylex.(*parser).newMap() + yyVAL.descriptors["counter_reset_hint"] = yyDollar[3].item } case 183: + yyDollar = yyS[yypt-4 : yypt+1] + { + yyVAL.bucket_set = yyDollar[2].bucket_set + } + case 184: + yyDollar = yyS[yypt-3 : yypt+1] + { + yyVAL.bucket_set = yyDollar[2].bucket_set + } + case 185: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.bucket_set = append(yyDollar[1].bucket_set, yyDollar[3].float) } - case 184: + case 186: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.bucket_set = []float64{yyDollar[1].float} } - case 240: + case 244: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.node = &NumberLiteral{ @@ -1993,7 +2004,7 @@ yydefault: PosRange: yyDollar[1].item.PositionRange(), } } - case 241: + case 245: yyDollar = yyS[yypt-1 : yypt+1] { var err error @@ -2008,12 +2019,12 @@ yydefault: Duration: true, } } - case 242: + case 246: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.float = yylex.(*parser).number(yyDollar[1].item.Val) } - case 243: + case 247: yyDollar = yyS[yypt-1 : yypt+1] { var err error @@ -2024,17 +2035,17 @@ yydefault: } yyVAL.float = dur.Seconds() } - case 244: + case 248: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.float = yyDollar[2].float } - case 245: + case 249: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.float = -yyDollar[2].float } - case 248: + case 252: yyDollar = yyS[yypt-1 : yypt+1] { var err error @@ -2043,17 +2054,17 @@ yydefault: yylex.(*parser).addParseErrf(yyDollar[1].item.PositionRange(), "invalid repetition in series values: %s", err) } } - case 249: + case 253: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.int = -int64(yyDollar[2].uint) } - case 250: + case 254: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.int = int64(yyDollar[1].uint) } - case 251: + case 255: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.node = &StringLiteral{ @@ -2061,7 +2072,7 @@ yydefault: PosRange: yyDollar[1].item.PositionRange(), } } - case 252: + case 256: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.item = Item{ @@ -2070,12 +2081,12 @@ yydefault: Val: yylex.(*parser).unquoteString(yyDollar[1].item.Val), } } - case 253: + case 257: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.strings = nil } - case 255: + case 259: yyDollar = yyS[yypt-1 : yypt+1] { nl := yyDollar[1].node.(*NumberLiteral) @@ -2086,7 +2097,7 @@ yydefault: } yyVAL.node = nl } - case 256: + case 260: yyDollar = yyS[yypt-2 : yypt+1] { nl := yyDollar[2].node.(*NumberLiteral) @@ -2101,7 +2112,7 @@ yydefault: nl.PosRange.Start = yyDollar[1].item.Pos yyVAL.node = nl } - case 257: + case 261: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2110,7 +2121,7 @@ yydefault: EndPos: yyDollar[3].item.PositionRange().End, } } - case 258: + case 262: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2123,7 +2134,7 @@ yydefault: StartPos: yyDollar[1].item.Pos, } } - case 259: + case 263: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2134,7 +2145,7 @@ yydefault: RHS: yyDollar[5].node.(Expr), } } - case 260: + case 264: yyDollar = yyS[yypt-7 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2150,7 +2161,7 @@ yydefault: }, } } - case 261: + case 265: yyDollar = yyS[yypt-4 : yypt+1] { de := yyDollar[3].node.(*DurationExpr) @@ -2165,7 +2176,7 @@ yydefault: } yyVAL.node = yyDollar[3].node } - case 265: + case 269: yyDollar = yyS[yypt-1 : yypt+1] { nl := yyDollar[1].node.(*NumberLiteral) @@ -2176,7 +2187,7 @@ yydefault: } yyVAL.node = nl } - case 266: + case 270: yyDollar = yyS[yypt-2 : yypt+1] { switch expr := yyDollar[2].node.(type) { @@ -2209,25 +2220,25 @@ yydefault: break } } - case 267: + case 271: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) yyVAL.node = &DurationExpr{Op: ADD, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 268: + case 272: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) yyVAL.node = &DurationExpr{Op: SUB, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 269: + case 273: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) yyVAL.node = &DurationExpr{Op: MUL, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 270: + case 274: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) @@ -2238,7 +2249,7 @@ yydefault: } yyVAL.node = &DurationExpr{Op: DIV, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 271: + case 275: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) @@ -2249,13 +2260,13 @@ yydefault: } yyVAL.node = &DurationExpr{Op: MOD, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 272: + case 276: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) yyVAL.node = &DurationExpr{Op: POW, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 273: + case 277: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2264,7 +2275,7 @@ yydefault: EndPos: yyDollar[3].item.PositionRange().End, } } - case 274: + case 278: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2275,7 +2286,7 @@ yydefault: RHS: yyDollar[5].node.(Expr), } } - case 276: + case 280: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[2].node.(Expr)) diff --git a/promql/parser/parse_test.go b/promql/parser/parse_test.go index e0d6ae77f2..8d50d8c255 100644 --- a/promql/parser/parse_test.go +++ b/promql/parser/parse_test.go @@ -798,6 +798,28 @@ var testExpr = []struct { EndPos: 21, }, }, + { + input: `anchored{job="test"}`, + expected: &VectorSelector{ + Name: "anchored", + LabelMatchers: []*labels.Matcher{ + MustLabelMatcher(labels.MatchEqual, "job", "test"), + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "anchored"), + }, + PosRange: posrange.PositionRange{Start: 0, End: 20}, + }, + }, + { + input: `smoothed{job="test"}`, + expected: &VectorSelector{ + Name: "smoothed", + LabelMatchers: []*labels.Matcher{ + MustLabelMatcher(labels.MatchEqual, "job", "test"), + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "smoothed"), + }, + PosRange: posrange.PositionRange{Start: 0, End: 20}, + }, + }, // Vector binary operations. { input: "foo * bar", @@ -2773,6 +2795,36 @@ var testExpr = []struct { PosRange: posrange.PositionRange{Start: 0, End: 25}, }, }, + { + input: "sum by (anchored)(some_metric)", + expected: &AggregateExpr{ + Op: SUM, + Expr: &VectorSelector{ + Name: "some_metric", + LabelMatchers: []*labels.Matcher{ + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "some_metric"), + }, + PosRange: posrange.PositionRange{Start: 18, End: 29}, + }, + Grouping: []string{"anchored"}, + PosRange: posrange.PositionRange{Start: 0, End: 30}, + }, + }, + { + input: "sum by (smoothed)(some_metric)", + expected: &AggregateExpr{ + Op: SUM, + Expr: &VectorSelector{ + Name: "some_metric", + LabelMatchers: []*labels.Matcher{ + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "some_metric"), + }, + PosRange: posrange.PositionRange{Start: 18, End: 29}, + }, + Grouping: []string{"smoothed"}, + PosRange: posrange.PositionRange{Start: 0, End: 30}, + }, + }, { input: `sum by ("foo bar")({"some.metric"})`, expected: &AggregateExpr{ From b7c3a2194f3396d7f1d0dec73a388d1d82cbeaee Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Fri, 17 Oct 2025 12:17:32 +0200 Subject: [PATCH 12/14] Fix formatting of range vector selectors with smoothed/anchored modifier The modifiers were already printed as part of the VectorSelector, so for: `foo[5m] anchored` ...the output was: `foo anchored[5m] anchored` Similar to how it was already done for `@` and `offset`, I now removed these modifiers in the copy of the vector selector that is used to print the matrix selector. I also removed some unused code that restored the copy of the vector selector after overwriting its fields. AFAICS there was no use in doing that, since it was a copy already that would just be thrown away after printing, and the original selector wasn't affected. I also removed an erroneous comment in `atOffset()` where no actual copying took place and no fields were overwritten. Signed-off-by: Julius Volz --- promql/parser/printer.go | 14 ++++++-------- promql/parser/printer_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/promql/parser/printer.go b/promql/parser/printer.go index 6bfc8d41e9..a562b88044 100644 --- a/promql/parser/printer.go +++ b/promql/parser/printer.go @@ -229,7 +229,6 @@ func (node *Call) ShortString() string { } func (node *MatrixSelector) atOffset() (string, string) { - // Copy the Vector selector before changing the offset vecSelector := node.VectorSelector.(*VectorSelector) offset := "" switch { @@ -254,20 +253,21 @@ func (node *MatrixSelector) atOffset() (string, string) { func (node *MatrixSelector) String() string { at, offset := node.atOffset() - // Copy the Vector selector before changing the offset + // Copy the Vector selector so we can modify it to not print @, offset, and other modifiers twice. vecSelector := *node.VectorSelector.(*VectorSelector) - // Do not print the @ and offset twice. - offsetVal, offsetExprVal, atVal, preproc := vecSelector.OriginalOffset, vecSelector.OriginalOffsetExpr, vecSelector.Timestamp, vecSelector.StartOrEnd + anchored, smoothed := vecSelector.Anchored, vecSelector.Smoothed vecSelector.OriginalOffset = 0 vecSelector.OriginalOffsetExpr = nil vecSelector.Timestamp = nil vecSelector.StartOrEnd = 0 + vecSelector.Anchored = false + vecSelector.Smoothed = false extendedAttribute := "" switch { - case vecSelector.Anchored: + case anchored: extendedAttribute = " anchored" - case vecSelector.Smoothed: + case smoothed: extendedAttribute = " smoothed" } rangeStr := model.Duration(node.Range).String() @@ -276,8 +276,6 @@ func (node *MatrixSelector) String() string { } str := fmt.Sprintf("%s[%s]%s%s%s", vecSelector.String(), rangeStr, extendedAttribute, at, offset) - vecSelector.OriginalOffset, vecSelector.OriginalOffsetExpr, vecSelector.Timestamp, vecSelector.StartOrEnd = offsetVal, offsetExprVal, atVal, preproc - return str } diff --git a/promql/parser/printer_test.go b/promql/parser/printer_test.go index 0248d280d4..c9febc61fc 100644 --- a/promql/parser/printer_test.go +++ b/promql/parser/printer_test.go @@ -115,6 +115,36 @@ func TestExprString(t *testing.T) { { in: `a[1h:5m] offset 1m`, }, + { + in: `a anchored`, + }, + { + in: `a[5m] anchored`, + }, + { + in: `a{b="c"}[5m] anchored`, + }, + { + in: `a{b="c"}[5m] anchored offset 1m`, + }, + { + in: `a{b="c"}[5m] anchored @ start() offset 1m`, + }, + { + in: `a smoothed`, + }, + { + in: `a[5m] smoothed`, + }, + { + in: `a{b="c"}[5m] smoothed`, + }, + { + in: `a{b="c"}[5m] smoothed offset 1m`, + }, + { + in: `a{b="c"}[5m] smoothed @ start() offset 1m`, + }, { in: `{__name__="a"}`, }, @@ -222,6 +252,8 @@ func TestExprString(t *testing.T) { }, } + EnableExtendedRangeSelectors = true + for _, test := range inputs { t.Run(test.in, func(t *testing.T) { expr, err := ParseExpr(test.in) From 9d7d544be1530878f526370b244589de9eb94d40 Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Fri, 17 Oct 2025 12:30:57 +0200 Subject: [PATCH 13/14] Disable extended range selector modifiers again after test run Signed-off-by: Julius Volz --- promql/parser/printer_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/promql/parser/printer_test.go b/promql/parser/printer_test.go index c9febc61fc..06ecbf175f 100644 --- a/promql/parser/printer_test.go +++ b/promql/parser/printer_test.go @@ -253,6 +253,9 @@ func TestExprString(t *testing.T) { } EnableExtendedRangeSelectors = true + t.Cleanup(func() { + EnableExtendedRangeSelectors = false + }) for _, test := range inputs { t.Run(test.in, func(t *testing.T) { From 09e7111aa7be932ec30202c0aaf8f56510d2bc11 Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Fri, 17 Oct 2025 17:17:48 +0200 Subject: [PATCH 14/14] UI: Fix double-loading of API data on pages with slow rendering (#17357) Without `staleTime: Infinity`, the query data would be immediately marked stale, and in combination with the `gcTime: 0` setting and a brief unmount during data loading (via Suspense), the data would have to be reloaded a second time during/after the first real render. `gcTime: 0` + `staleTime: Infinity` should give us the desired behavior where data loaded for a page should be valid forever as long as that page is being displayed, but always thrown away (and later reloaded) whenever we navigate away and again to that page. Signed-off-by: Julius Volz --- web/ui/mantine-ui/src/api/api.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/web/ui/mantine-ui/src/api/api.ts b/web/ui/mantine-ui/src/api/api.ts index f1dd2b8c0c..18541751b5 100644 --- a/web/ui/mantine-ui/src/api/api.ts +++ b/web/ui/mantine-ui/src/api/api.ts @@ -125,6 +125,7 @@ export const useSuspenseAPIQuery = ({ key, path, params }: QueryOptions) => { queryKey: key !== undefined ? key : [path, params], retry: false, refetchOnWindowFocus: false, + staleTime: Infinity, // Required for suspense queries since the component is briefly unmounted when loading the data, which together with a gcTime of 0 will cause the data to be garbage collected before it can be used. gcTime: 0, queryFn: createQueryFn({ pathPrefix, path, params }), });