From c8e0b6f97cd8121abc3f5fdb359c21dcd79f5d72 Mon Sep 17 00:00:00 2001 From: Martin Valiente Ainz <64830185+tinitiuset@users.noreply.github.com> Date: Mon, 2 Feb 2026 13:05:36 +0100 Subject: [PATCH] Replace per-component parser options with default instance Signed-off-by: Martin Valiente Ainz <64830185+tinitiuset@users.noreply.github.com> --- cmd/prometheus/main.go | 6 +++--- cmd/promtool/main.go | 11 +++++----- cmd/promtool/main_test.go | 5 ++--- cmd/promtool/rules.go | 1 - cmd/promtool/unittest.go | 11 +++++----- model/rulefmt/rulefmt.go | 16 +++++++------- model/rulefmt/rulefmt_test.go | 19 +++++++---------- promql/bench_test.go | 4 +--- promql/engine.go | 11 +++------- promql/engine_test.go | 40 +++++++++++++---------------------- promql/parser/parse.go | 16 +++++++++++++- promql/promql_test.go | 8 +++---- promql/promqltest/test.go | 12 +++++------ rules/manager.go | 22 ++++++++----------- rules/manager_test.go | 2 +- web/api/v1/api.go | 13 +++++------- web/api/v1/errors_test.go | 2 -- web/api/v1/test_helpers.go | 2 -- web/web.go | 3 --- 19 files changed, 91 insertions(+), 113 deletions(-) diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go index c381e36829..71fae138f7 100644 --- a/cmd/prometheus/main.go +++ b/cmd/prometheus/main.go @@ -632,6 +632,9 @@ func main() { os.Exit(1) } + // Set the process-wide parser configuration. All components (engine, rules, web) use this. + parser.SetDefaultOptions(cfg.parserOpts) + if agentMode && len(serverOnlyFlags) > 0 { fmt.Fprintf(os.Stderr, "The following flag(s) can not be used in agent mode: %q", serverOnlyFlags) os.Exit(3) @@ -935,7 +938,6 @@ func main() { EnablePerStepStats: cfg.enablePerStepStats, EnableDelayedNameRemoval: cfg.promqlEnableDelayedNameRemoval, EnableTypeAndUnitLabels: cfg.scrape.EnableTypeAndUnitLabels, - ParserOptions: cfg.parserOpts, FeatureRegistry: features.DefaultRegistry, } @@ -956,7 +958,6 @@ func main() { ResendDelay: time.Duration(cfg.resendDelay), MaxConcurrentEvals: cfg.maxConcurrentEvals, ConcurrentEvalsEnabled: cfg.enableConcurrentRuleEval, - ParserOptions: cfg.parserOpts, DefaultRuleQueryOffset: func() time.Duration { return time.Duration(cfgFile.GlobalConfig.RuleQueryOffset) }, @@ -974,7 +975,6 @@ func main() { cfg.web.Storage = fanoutStorage cfg.web.ExemplarStorage = localStorage cfg.web.QueryEngine = queryEngine - cfg.web.ParserOptions = cfg.parserOpts cfg.web.ScrapeManager = scrapeManager cfg.web.RuleManager = ruleManager cfg.web.Notifier = notifierManager diff --git a/cmd/promtool/main.go b/cmd/promtool/main.go index de58d45040..d55881a9de 100644 --- a/cmd/promtool/main.go +++ b/cmd/promtool/main.go @@ -361,6 +361,7 @@ func main() { } } } + parser.SetDefaultOptions(promtoolParserOpts) switch parsedCmd { case sdCheckCmd.FullCommand(): @@ -869,7 +870,7 @@ func checkRulesFromStdin(ls rulesLintConfig) (bool, bool) { fmt.Fprintln(os.Stderr, " FAILED:", err) return true, true } - rgs, errs := rulefmt.Parse(data, ls.ignoreUnknownFields, ls.nameValidationScheme, promtoolParserOpts) + rgs, errs := rulefmt.Parse(data, ls.ignoreUnknownFields, ls.nameValidationScheme) if errs != nil { failed = true fmt.Fprintln(os.Stderr, " FAILED:") @@ -903,7 +904,7 @@ func checkRules(files []string, ls rulesLintConfig) (bool, bool) { hasErrors := false for _, f := range files { fmt.Println("Checking", f) - rgs, errs := rulefmt.ParseFile(f, ls.ignoreUnknownFields, ls.nameValidationScheme, promtoolParserOpts) + rgs, errs := rulefmt.ParseFile(f, ls.ignoreUnknownFields, ls.nameValidationScheme) if errs != nil { failed = true fmt.Fprintln(os.Stderr, " FAILED:") @@ -1345,7 +1346,7 @@ func checkTargetGroupsForScrapeConfig(targetGroups []*targetgroup.Group, scfg *c } func formatPromQL(query string) error { - expr, err := parser.ParseExpr(query, parser.WithOptions(promtoolParserOpts)) + expr, err := parser.ParseExpr(query) if err != nil { return err } @@ -1355,7 +1356,7 @@ func formatPromQL(query string) error { } func labelsSetPromQL(query, labelMatchType, name, value string) error { - expr, err := parser.ParseExpr(query, parser.WithOptions(promtoolParserOpts)) + expr, err := parser.ParseExpr(query) if err != nil { return err } @@ -1400,7 +1401,7 @@ func labelsSetPromQL(query, labelMatchType, name, value string) error { } func labelsDeletePromQL(query, name string) error { - expr, err := parser.ParseExpr(query, parser.WithOptions(promtoolParserOpts)) + expr, err := parser.ParseExpr(query) if err != nil { return err } diff --git a/cmd/promtool/main_test.go b/cmd/promtool/main_test.go index 557090d3ce..9e6e7268f7 100644 --- a/cmd/promtool/main_test.go +++ b/cmd/promtool/main_test.go @@ -37,7 +37,6 @@ import ( "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/model/rulefmt" - "github.com/prometheus/prometheus/promql/parser" "github.com/prometheus/prometheus/promql/promqltest" ) @@ -188,7 +187,7 @@ func TestCheckDuplicates(t *testing.T) { c := test t.Run(c.name, func(t *testing.T) { t.Parallel() - rgs, err := rulefmt.ParseFile(c.ruleFile, false, model.UTF8Validation, parser.Options{}) + rgs, err := rulefmt.ParseFile(c.ruleFile, false, model.UTF8Validation) require.Empty(t, err) dups := checkDuplicates(rgs.Groups) require.Equal(t, c.expectedDups, dups) @@ -197,7 +196,7 @@ func TestCheckDuplicates(t *testing.T) { } func BenchmarkCheckDuplicates(b *testing.B) { - rgs, err := rulefmt.ParseFile("./testdata/rules_large.yml", false, model.UTF8Validation, parser.Options{}) + rgs, err := rulefmt.ParseFile("./testdata/rules_large.yml", false, model.UTF8Validation) require.Empty(b, err) for b.Loop() { diff --git a/cmd/promtool/rules.go b/cmd/promtool/rules.go index d80d2347e6..bb45178e9c 100644 --- a/cmd/promtool/rules.go +++ b/cmd/promtool/rules.go @@ -66,7 +66,6 @@ func newRuleImporter(logger *slog.Logger, config ruleImporterConfig, apiClient q apiClient: apiClient, ruleManager: rules.NewManager(&rules.ManagerOptions{ NameValidationScheme: config.nameValidationScheme, - ParserOptions: promtoolParserOpts, }), } } diff --git a/cmd/promtool/unittest.go b/cmd/promtool/unittest.go index 357f1f6da5..105e626eba 100644 --- a/cmd/promtool/unittest.go +++ b/cmd/promtool/unittest.go @@ -247,12 +247,11 @@ func (tg *testGroup) test(testname string, evalInterval time.Duration, groupOrde // Load the rule files. opts := &rules.ManagerOptions{ - QueryFunc: rules.EngineQueryFunc(suite.QueryEngine(), suite.Storage()), - Appendable: suite.Storage(), - Context: context.Background(), - NotifyFunc: func(context.Context, string, ...*rules.Alert) {}, - Logger: promslog.NewNopLogger(), - ParserOptions: promtoolParserOpts, + QueryFunc: rules.EngineQueryFunc(suite.QueryEngine(), suite.Storage()), + Appendable: suite.Storage(), + Context: context.Background(), + NotifyFunc: func(context.Context, string, ...*rules.Alert) {}, + Logger: promslog.NewNopLogger(), } m := rules.NewManager(opts) groupsMap, ers := m.LoadGroups(time.Duration(tg.Interval), tg.ExternalLabels, tg.ExternalURL, nil, ignoreUnknownFields, ruleFiles...) diff --git a/model/rulefmt/rulefmt.go b/model/rulefmt/rulefmt.go index bf72a863aa..2cbfdf4cfc 100644 --- a/model/rulefmt/rulefmt.go +++ b/model/rulefmt/rulefmt.go @@ -97,7 +97,7 @@ type ruleGroups struct { } // Validate validates all rules in the rule groups. -func (g *RuleGroups) Validate(node ruleGroups, nameValidationScheme model.ValidationScheme, parserOpts parser.Options) (errs []error) { +func (g *RuleGroups) Validate(node ruleGroups, nameValidationScheme model.ValidationScheme) (errs []error) { if err := namevalidationutil.CheckNameValidationScheme(nameValidationScheme); err != nil { errs = append(errs, err) return errs @@ -134,7 +134,7 @@ func (g *RuleGroups) Validate(node ruleGroups, nameValidationScheme model.Valida set[g.Name] = struct{}{} for i, r := range g.Rules { - for _, node := range r.Validate(node.Groups[j].Rules[i], nameValidationScheme, parserOpts) { + for _, node := range r.Validate(node.Groups[j].Rules[i], nameValidationScheme) { var ruleName string if r.Alert != "" { ruleName = r.Alert @@ -198,7 +198,7 @@ type RuleNode struct { } // Validate the rule and return a list of encountered errors. -func (r *Rule) Validate(node RuleNode, nameValidationScheme model.ValidationScheme, parserOpts parser.Options) (nodes []WrappedError) { +func (r *Rule) Validate(node RuleNode, nameValidationScheme model.ValidationScheme) (nodes []WrappedError) { if r.Record != "" && r.Alert != "" { nodes = append(nodes, WrappedError{ err: errors.New("only one of 'record' and 'alert' must be set"), @@ -219,7 +219,7 @@ func (r *Rule) Validate(node RuleNode, nameValidationScheme model.ValidationSche err: errors.New("field 'expr' must be set in rule"), node: &node.Expr, }) - } else if _, err := parser.ParseExpr(r.Expr, parser.WithOptions(parserOpts)); err != nil { + } else if _, err := parser.ParseExpr(r.Expr); err != nil { nodes = append(nodes, WrappedError{ err: fmt.Errorf("could not parse expression: %w", err), node: &node.Expr, @@ -339,7 +339,7 @@ func testTemplateParsing(rl *Rule) (errs []error) { } // Parse parses and validates a set of rules. -func Parse(content []byte, ignoreUnknownFields bool, nameValidationScheme model.ValidationScheme, parserOpts parser.Options) (*RuleGroups, []error) { +func Parse(content []byte, ignoreUnknownFields bool, nameValidationScheme model.ValidationScheme) (*RuleGroups, []error) { var ( groups RuleGroups node ruleGroups @@ -364,16 +364,16 @@ func Parse(content []byte, ignoreUnknownFields bool, nameValidationScheme model. return nil, errs } - return &groups, groups.Validate(node, nameValidationScheme, parserOpts) + return &groups, groups.Validate(node, nameValidationScheme) } // ParseFile reads and parses rules from a file. -func ParseFile(file string, ignoreUnknownFields bool, nameValidationScheme model.ValidationScheme, parserOpts parser.Options) (*RuleGroups, []error) { +func ParseFile(file string, ignoreUnknownFields bool, nameValidationScheme model.ValidationScheme) (*RuleGroups, []error) { b, err := os.ReadFile(file) if err != nil { return nil, []error{fmt.Errorf("%s: %w", file, err)} } - rgs, errs := Parse(b, ignoreUnknownFields, nameValidationScheme, parserOpts) + rgs, errs := Parse(b, ignoreUnknownFields, nameValidationScheme) for i := range errs { errs[i] = fmt.Errorf("%s: %w", file, errs[i]) } diff --git a/model/rulefmt/rulefmt_test.go b/model/rulefmt/rulefmt_test.go index 52c2abfb1d..ea8d09af0d 100644 --- a/model/rulefmt/rulefmt_test.go +++ b/model/rulefmt/rulefmt_test.go @@ -22,20 +22,17 @@ import ( "github.com/prometheus/common/model" "github.com/stretchr/testify/require" "go.yaml.in/yaml/v3" - - "github.com/prometheus/prometheus/promql/parser" ) func TestParseFileSuccess(t *testing.T) { - opts := parser.Options{} - _, errs := ParseFile("testdata/test.yaml", false, model.UTF8Validation, opts) + _, errs := ParseFile("testdata/test.yaml", false, model.UTF8Validation) require.Empty(t, errs, "unexpected errors parsing file") - _, errs = ParseFile("testdata/utf-8_lname.good.yaml", false, model.UTF8Validation, opts) + _, errs = ParseFile("testdata/utf-8_lname.good.yaml", false, model.UTF8Validation) require.Empty(t, errs, "unexpected errors parsing file") - _, errs = ParseFile("testdata/utf-8_annotation.good.yaml", false, model.UTF8Validation, opts) + _, errs = ParseFile("testdata/utf-8_annotation.good.yaml", false, model.UTF8Validation) require.Empty(t, errs, "unexpected errors parsing file") - _, errs = ParseFile("testdata/legacy_validation_annotation.good.yaml", false, model.LegacyValidation, opts) + _, errs = ParseFile("testdata/legacy_validation_annotation.good.yaml", false, model.LegacyValidation) require.Empty(t, errs, "unexpected errors parsing file") } @@ -44,7 +41,7 @@ func TestParseFileSuccessWithAliases(t *testing.T) { / sum without(instance) (rate(requests_total[5m])) ` - rgs, errs := ParseFile("testdata/test_aliases.yaml", false, model.UTF8Validation, parser.Options{}) + rgs, errs := ParseFile("testdata/test_aliases.yaml", false, model.UTF8Validation) require.Empty(t, errs, "unexpected errors parsing file") for _, rg := range rgs.Groups { require.Equal(t, "HighAlert", rg.Rules[0].Alert) @@ -122,7 +119,7 @@ func TestParseFileFailure(t *testing.T) { if c.nameValidationScheme == model.UnsetValidation { c.nameValidationScheme = model.UTF8Validation } - _, errs := ParseFile(filepath.Join("testdata", c.filename), false, c.nameValidationScheme, parser.Options{}) + _, errs := ParseFile(filepath.Join("testdata", c.filename), false, c.nameValidationScheme) require.NotEmpty(t, errs, "Expected error parsing %s but got none", c.filename) require.ErrorContainsf(t, errs[0], c.errMsg, "Expected error for %s.", c.filename) }) @@ -218,7 +215,7 @@ groups: } for _, tst := range tests { - rgs, errs := Parse([]byte(tst.ruleString), false, model.UTF8Validation, parser.Options{}) + rgs, errs := Parse([]byte(tst.ruleString), false, model.UTF8Validation) require.NotNil(t, rgs, "Rule parsing, rule=\n"+tst.ruleString) passed := (tst.shouldPass && len(errs) == 0) || (!tst.shouldPass && len(errs) > 0) require.True(t, passed, "Rule validation failed, rule=\n"+tst.ruleString) @@ -245,7 +242,7 @@ groups: annotations: summary: "Instance {{ $labels.instance }} up" ` - _, errs := Parse([]byte(group), false, model.UTF8Validation, parser.Options{}) + _, errs := Parse([]byte(group), false, model.UTF8Validation) require.Len(t, errs, 2, "Expected two errors") var err00 *Error require.ErrorAs(t, errs[0], &err00) diff --git a/promql/bench_test.go b/promql/bench_test.go index f82fac5d2e..03b143718f 100644 --- a/promql/bench_test.go +++ b/promql/bench_test.go @@ -335,14 +335,12 @@ func BenchmarkRangeQuery(b *testing.B) { stor := teststorage.New(b) stor.DisableCompactions() // Don't want auto-compaction disrupting timings. + parser.SetDefaultOptions(parser.Options{EnableExtendedRangeSelectors: true}) opts := promql.EngineOpts{ Logger: nil, Reg: nil, MaxSamples: 50000000, Timeout: 100 * time.Second, - ParserOptions: parser.Options{ - EnableExtendedRangeSelectors: true, - }, } engine := promqltest.NewTestEngineWithOpts(b, opts) diff --git a/promql/engine.go b/promql/engine.go index e6deb97ab3..d90f4910c2 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -332,9 +332,6 @@ type EngineOpts struct { // EnableTypeAndUnitLabels will allow PromQL Engine to make decisions based on the type and unit labels. EnableTypeAndUnitLabels bool - // ParserOptions is the parser configuration used when parsing queries. - ParserOptions parser.Options - // FeatureRegistry is the registry for tracking enabled/disabled features. FeatureRegistry features.Collector } @@ -356,7 +353,6 @@ type Engine struct { enablePerStepStats bool enableDelayedNameRemoval bool enableTypeAndUnitLabels bool - parserOptions parser.Options } // NewEngine returns a new engine. @@ -463,7 +459,7 @@ func NewEngine(opts EngineOpts) *Engine { r.Enable(features.PromQL, "per_query_lookback_delta") r.Enable(features.PromQL, "subqueries") - parser.RegisterFeatures(r, opts.ParserOptions) + parser.RegisterFeatures(r, parser.DefaultOptions()) } return &Engine{ @@ -479,7 +475,6 @@ func NewEngine(opts EngineOpts) *Engine { enablePerStepStats: opts.EnablePerStepStats, enableDelayedNameRemoval: opts.EnableDelayedNameRemoval, enableTypeAndUnitLabels: opts.EnableTypeAndUnitLabels, - parserOptions: opts.ParserOptions, } } @@ -528,7 +523,7 @@ func (ng *Engine) NewInstantQuery(ctx context.Context, q storage.Queryable, opts return nil, err } defer finishQueue() - expr, err := parser.ParseExpr(qs, parser.WithOptions(ng.parserOptions)) + expr, err := parser.ParseExpr(qs) if err != nil { return nil, err } @@ -549,7 +544,7 @@ func (ng *Engine) NewRangeQuery(ctx context.Context, q storage.Queryable, opts Q return nil, err } defer finishQueue() - expr, err := parser.ParseExpr(qs, parser.WithOptions(ng.parserOptions)) + expr, err := parser.ParseExpr(qs) if err != nil { return nil, err } diff --git a/promql/engine_test.go b/promql/engine_test.go index bff7b0d467..e58e9302a4 100644 --- a/promql/engine_test.go +++ b/promql/engine_test.go @@ -1653,7 +1653,7 @@ func TestExtendedRangeSelectors(t *testing.T) { } } -// TestParserConfigIsolation ensures that parser configuration is per-engine and not global. +// TestParserConfigIsolation ensures the default parser configuration is respected. func TestParserConfigIsolation(t *testing.T) { ctx := context.Background() storage := promqltest.LoadedStorage(t, ` @@ -1662,30 +1662,20 @@ func TestParserConfigIsolation(t *testing.T) { `) t.Cleanup(func() { storage.Close() }) - // Engine with extended range selectors disabled: "smoothed" is not valid. - optsDisabled := promql.EngineOpts{ - MaxSamples: 1000, - Timeout: 10 * time.Second, - ParserOptions: parser.Options{EnableExtendedRangeSelectors: false}, - } - engineDisabled := promql.NewEngine(optsDisabled) - - // Engine with extended range selectors enabled: "smoothed" is valid. - optsEnabled := promql.EngineOpts{ - MaxSamples: 1000, - Timeout: 10 * time.Second, - ParserOptions: parser.Options{EnableExtendedRangeSelectors: true}, - } - engineEnabled := promql.NewEngine(optsEnabled) - query := "metric[10s] smoothed" t.Run("engine_with_feature_disabled_rejects", func(t *testing.T) { - _, err := engineDisabled.NewInstantQuery(ctx, storage, nil, query, time.Unix(10, 0)) + parser.SetDefaultOptions(parser.Options{EnableExtendedRangeSelectors: false}) + engine := promql.NewEngine(promql.EngineOpts{MaxSamples: 1000, Timeout: 10 * time.Second}) + t.Cleanup(func() { _ = engine.Close() }) + _, err := engine.NewInstantQuery(ctx, storage, nil, query, time.Unix(10, 0)) require.Error(t, err) require.Contains(t, err.Error(), "parse") }) t.Run("engine_with_feature_enabled_accepts", func(t *testing.T) { - q, err := engineEnabled.NewInstantQuery(ctx, storage, nil, query, time.Unix(10, 0)) + parser.SetDefaultOptions(parser.Options{EnableExtendedRangeSelectors: true}) + engine := promql.NewEngine(promql.EngineOpts{MaxSamples: 1000, Timeout: 10 * time.Second}) + t.Cleanup(func() { _ = engine.Close() }) + q, err := engine.NewInstantQuery(ctx, storage, nil, query, time.Unix(10, 0)) require.NoError(t, err) defer q.Close() res := q.Exec(ctx) @@ -3868,6 +3858,12 @@ func (s mockSeries) Iterator(it chunkenc.Iterator) chunkenc.Iterator { } func TestEvaluationWithDelayedNameRemovalDisabled(t *testing.T) { + parser.SetDefaultOptions(parser.Options{ + EnableExperimentalFunctions: true, + ExperimentalDurationExpr: true, + EnableExtendedRangeSelectors: true, + EnableBinopFillModifiers: true, + }) opts := promql.EngineOpts{ Logger: nil, Reg: nil, @@ -3875,12 +3871,6 @@ func TestEvaluationWithDelayedNameRemovalDisabled(t *testing.T) { MaxSamples: 10000, Timeout: 10 * time.Second, EnableDelayedNameRemoval: false, - ParserOptions: parser.Options{ - EnableExperimentalFunctions: true, - ExperimentalDurationExpr: true, - EnableExtendedRangeSelectors: true, - EnableBinopFillModifiers: true, - }, } engine := promqltest.NewTestEngineWithOpts(t, opts) diff --git a/promql/parser/parse.go b/promql/parser/parse.go index 5452b6190c..d634c33101 100644 --- a/promql/parser/parse.go +++ b/promql/parser/parse.go @@ -39,6 +39,20 @@ var parserPool = sync.Pool{ }, } +// defaultOptions is the default parser configuration. +var defaultOptions Options + +// SetDefaultOptions sets the default parser configuration. +// It should be called once at startup before any parsing; after that, the value must not be modified. +func SetDefaultOptions(opts Options) { + defaultOptions = opts +} + +// DefaultOptions returns the default parser configuration. +func DefaultOptions() Options { + return defaultOptions +} + // Options holds the configuration for the PromQL parser. type Options struct { EnableExperimentalFunctions bool @@ -101,7 +115,7 @@ func NewParser(input string, opts ...Opt) *parser { //nolint:revive // unexporte p.parseErrors = nil p.generatedParserResult = nil p.lastClosing = posrange.Pos(0) - p.options = Options{} + p.options = DefaultOptions() // Clear lexer struct before reusing. p.lex = Lexer{ diff --git a/promql/promql_test.go b/promql/promql_test.go index d1945f02da..728c2a00e4 100644 --- a/promql/promql_test.go +++ b/promql/promql_test.go @@ -40,15 +40,15 @@ func TestEvaluations(t *testing.T) { func TestConcurrentRangeQueries(t *testing.T) { stor := teststorage.New(t) + parser.SetDefaultOptions(parser.Options{ + EnableExperimentalFunctions: true, + EnableExtendedRangeSelectors: true, + }) opts := promql.EngineOpts{ Logger: nil, Reg: nil, MaxSamples: 50000000, Timeout: 100 * time.Second, - ParserOptions: parser.Options{ - EnableExperimentalFunctions: true, - EnableExtendedRangeSelectors: true, - }, } engine := promqltest.NewTestEngineWithOpts(t, opts) diff --git a/promql/promqltest/test.go b/promql/promqltest/test.go index 494207a3dd..0c6ac3569d 100644 --- a/promql/promqltest/test.go +++ b/promql/promqltest/test.go @@ -88,6 +88,12 @@ func LoadedStorage(t testing.TB, input string) *teststorage.TestStorage { // NewTestEngine creates a promql.Engine with enablePerStepStats, lookbackDelta and maxSamples, and returns it. func NewTestEngine(tb testing.TB, enablePerStepStats bool, lookbackDelta time.Duration, maxSamples int) *promql.Engine { + parser.SetDefaultOptions(parser.Options{ + EnableExperimentalFunctions: true, + ExperimentalDurationExpr: true, + EnableExtendedRangeSelectors: true, + EnableBinopFillModifiers: true, + }) return NewTestEngineWithOpts(tb, promql.EngineOpts{ Logger: nil, Reg: nil, @@ -99,12 +105,6 @@ func NewTestEngine(tb testing.TB, enablePerStepStats bool, lookbackDelta time.Du EnablePerStepStats: enablePerStepStats, LookbackDelta: lookbackDelta, EnableDelayedNameRemoval: true, - ParserOptions: parser.Options{ - EnableExperimentalFunctions: true, - ExperimentalDurationExpr: true, - EnableExtendedRangeSelectors: true, - EnableBinopFillModifiers: true, - }, }) } diff --git a/rules/manager.go b/rules/manager.go index 7eec285a59..f32aead0aa 100644 --- a/rules/manager.go +++ b/rules/manager.go @@ -124,7 +124,6 @@ type ManagerOptions struct { ForGracePeriod time.Duration ResendDelay time.Duration GroupLoader GroupLoader - ParserOptions parser.Options DefaultRuleQueryOffset func() time.Duration MaxConcurrentEvals int64 ConcurrentEvalsEnabled bool @@ -160,7 +159,7 @@ func NewManager(o *ManagerOptions) *Manager { } if o.GroupLoader == nil { - o.GroupLoader = FileLoader{ParserOptions: o.ParserOptions} + o.GroupLoader = FileLoader{} } if o.RuleConcurrencyController == nil { @@ -321,18 +320,15 @@ type GroupLoader interface { } // FileLoader is the default GroupLoader implementation. It defers to rulefmt.ParseFile -// and parser.ParseExpr with the configured ParserOptions. -type FileLoader struct { - // ParserOptions is the parser configuration used when parsing rule expressions. - ParserOptions parser.Options +// and parser.ParseExpr and parser.DefaultOptions. +type FileLoader struct{} + +func (FileLoader) Load(identifier string, ignoreUnknownFields bool, nameValidationScheme model.ValidationScheme) (*rulefmt.RuleGroups, []error) { + return rulefmt.ParseFile(identifier, ignoreUnknownFields, nameValidationScheme) } -func (fl FileLoader) Load(identifier string, ignoreUnknownFields bool, nameValidationScheme model.ValidationScheme) (*rulefmt.RuleGroups, []error) { - return rulefmt.ParseFile(identifier, ignoreUnknownFields, nameValidationScheme, fl.ParserOptions) -} - -func (fl FileLoader) Parse(query string) (parser.Expr, error) { - return parser.ParseExpr(query, parser.WithOptions(fl.ParserOptions)) +func (FileLoader) Parse(query string) (parser.Expr, error) { + return parser.ParseExpr(query) } // LoadGroups reads groups from a list of files. @@ -632,7 +628,7 @@ func ParseFiles(patterns []string, nameValidationScheme model.ValidationScheme) } } for fn, pat := range files { - _, errs := rulefmt.ParseFile(fn, false, nameValidationScheme, parser.Options{}) + _, errs := rulefmt.ParseFile(fn, false, nameValidationScheme) if len(errs) > 0 { return fmt.Errorf("parse rules from file %q (pattern: %q): %w", fn, pat, errors.Join(errs...)) } diff --git a/rules/manager_test.go b/rules/manager_test.go index 01874002a2..3fcb90808e 100644 --- a/rules/manager_test.go +++ b/rules/manager_test.go @@ -809,7 +809,7 @@ func TestUpdate(t *testing.T) { } // Groups will be recreated if updated. - rgs, errs := rulefmt.ParseFile("fixtures/rules.yaml", false, model.UTF8Validation, parser.Options{}) + rgs, errs := rulefmt.ParseFile("fixtures/rules.yaml", false, model.UTF8Validation) require.Empty(t, errs, "file parsing failures") tmpFile, err := os.CreateTemp("", "rules.test.*.yaml") diff --git a/web/api/v1/api.go b/web/api/v1/api.go index f80459e8b1..225ef6911d 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -257,7 +257,6 @@ type API struct { codecs []Codec - parserOptions parser.Options featureRegistry features.Collector openAPIBuilder *OpenAPIBuilder } @@ -300,7 +299,6 @@ func NewAPI( enableTypeAndUnitLabels bool, appendMetadata bool, overrideErrorCode OverrideErrorCode, - parserOptions parser.Options, featureRegistry features.Collector, openAPIOptions OpenAPIOptions, ) *API { @@ -332,7 +330,6 @@ func NewAPI( notificationsGetter: notificationsGetter, notificationsSub: notificationsSub, overrideErrorCode: overrideErrorCode, - parserOptions: parserOptions, featureRegistry: featureRegistry, openAPIBuilder: NewOpenAPIBuilder(openAPIOptions, logger), @@ -565,8 +562,8 @@ func (api *API) query(r *http.Request) (result apiFuncResult) { }, nil, warnings, qry.Close} } -func (api *API) formatQuery(r *http.Request) (result apiFuncResult) { - expr, err := parser.ParseExpr(r.FormValue("query"), parser.WithOptions(api.parserOptions)) +func (*API) formatQuery(r *http.Request) (result apiFuncResult) { + expr, err := parser.ParseExpr(r.FormValue("query")) if err != nil { return invalidParamError(err, "query") } @@ -574,8 +571,8 @@ func (api *API) formatQuery(r *http.Request) (result apiFuncResult) { return apiFuncResult{expr.Pretty(0), nil, nil, nil} } -func (api *API) parseQuery(r *http.Request) apiFuncResult { - expr, err := parser.ParseExpr(r.FormValue("query"), parser.WithOptions(api.parserOptions)) +func (*API) parseQuery(r *http.Request) apiFuncResult { + expr, err := parser.ParseExpr(r.FormValue("query")) if err != nil { return invalidParamError(err, "query") } @@ -704,7 +701,7 @@ func (api *API) queryExemplars(r *http.Request) apiFuncResult { return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil} } - expr, err := parser.ParseExpr(r.FormValue("query"), parser.WithOptions(api.parserOptions)) + expr, err := parser.ParseExpr(r.FormValue("query")) if err != nil { return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil} } diff --git a/web/api/v1/errors_test.go b/web/api/v1/errors_test.go index 9e51d17a4a..850bedef17 100644 --- a/web/api/v1/errors_test.go +++ b/web/api/v1/errors_test.go @@ -34,7 +34,6 @@ import ( "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/promql" - "github.com/prometheus/prometheus/promql/parser" "github.com/prometheus/prometheus/promql/promqltest" "github.com/prometheus/prometheus/rules" "github.com/prometheus/prometheus/scrape" @@ -169,7 +168,6 @@ func createPrometheusAPI(t *testing.T, q storage.SampleAndChunkQueryable, overri false, false, overrideErrorCode, - parser.Options{}, nil, OpenAPIOptions{}, ) diff --git a/web/api/v1/test_helpers.go b/web/api/v1/test_helpers.go index 13306c47fb..2662b0c84b 100644 --- a/web/api/v1/test_helpers.go +++ b/web/api/v1/test_helpers.go @@ -20,7 +20,6 @@ import ( "github.com/prometheus/common/route" - "github.com/prometheus/prometheus/promql/parser" "github.com/prometheus/prometheus/web/api/testhelpers" ) @@ -102,7 +101,6 @@ func newTestAPI(t *testing.T, cfg testhelpers.APIConfig) *testhelpers.APIWrapper false, // enableTypeAndUnitLabels false, // appendMetadata nil, // overrideErrorCode - parser.Options{}, // parserOptions nil, // featureRegistry OpenAPIOptions{}, // openAPIOptions ) diff --git a/web/web.go b/web/web.go index 146774fe9a..cb9258d87f 100644 --- a/web/web.go +++ b/web/web.go @@ -53,7 +53,6 @@ import ( "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/notifier" "github.com/prometheus/prometheus/promql" - "github.com/prometheus/prometheus/promql/parser" "github.com/prometheus/prometheus/rules" "github.com/prometheus/prometheus/scrape" "github.com/prometheus/prometheus/storage" @@ -304,7 +303,6 @@ type Options struct { Gatherer prometheus.Gatherer Registerer prometheus.Registerer - ParserOptions parser.Options FeatureRegistry features.Collector } @@ -408,7 +406,6 @@ func New(logger *slog.Logger, o *Options) *Handler { o.EnableTypeAndUnitLabels, o.AppendMetadata, nil, - o.ParserOptions, o.FeatureRegistry, api_v1.OpenAPIOptions{ ExternalURL: o.ExternalURL.String(),