Skip to content

Commit f97c199

Browse files
committed
Register xfunctions in global parser for rule file loading
Signed-off-by: Paurush Garg <paurushg@amazon.com>
1 parent 74185ef commit f97c199

3 files changed

Lines changed: 72 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* [FEATURE] Querier: Add timeout classification to classify query timeouts as 4XX (user error) or 5XX (system error) based on phase timing. When enabled, queries that spend most of their time in PromQL evaluation return `422 Unprocessable Entity` instead of `503 Service Unavailable`. #7374
1313
* [FEATURE] Querier: Implement Resource Based Throttling in Querier. #7442
1414
* [FEATURE] Querier: Add resource-based query eviction that automatically cancels the heaviest running query when CPU or heap utilization exceeds configured thresholds. #7488
15+
* [BUGFIX] Ruler: Register xfunctions (xincrease, xrate, xdelta) in the global parser before loading rule files. #7621
1516
* [ENHANCEMENT] Upgrade prometheus alertmanager version to v0.32.1. #7462
1617
* [ENHANCEMENT] Tenant Federation: Avoid purging the regex resolver LRU cache on user-sync ticks when the set of known users has not changed. #7489
1718
* [ENHANCEMENT] Memberlist: Add `-memberlist.packet-read-timeout`, `-memberlist.max-packet-size`, and `-memberlist.max-concurrent-connections` flags to bound inbound gossip TCP connections, preventing slow-read, OOM, and connection-flood attacks on the gossip port. #7518

pkg/cortex/modules.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"flag"
66
"fmt"
77
"log/slog"
8+
"maps"
89
"net/http"
910
"runtime"
1011
"runtime/debug"
@@ -18,9 +19,11 @@ import (
1819
"github.com/prometheus/client_golang/prometheus"
1920
"github.com/prometheus/common/model"
2021
"github.com/prometheus/prometheus/promql"
22+
"github.com/prometheus/prometheus/promql/parser"
2123
"github.com/prometheus/prometheus/rules"
2224
prom_storage "github.com/prometheus/prometheus/storage"
2325
"github.com/thanos-io/objstore"
26+
"github.com/thanos-io/promql-engine/execution/parse"
2427
"github.com/thanos-io/thanos/pkg/discovery/dns"
2528
"github.com/thanos-io/thanos/pkg/querysharding"
2629
httpgrpc_server "github.com/weaveworks/common/httpgrpc/server"
@@ -661,6 +664,11 @@ func (t *Cortex) initRulerStorage() (serv services.Service, err error) {
661664
return
662665
}
663666

667+
// Register xfunctions (xincrease, xrate, xdelta) in the global parser
668+
if t.Cfg.Querier.ThanosEngine.EnableXFunctions {
669+
maps.Copy(parser.Functions, parse.XFunctions)
670+
}
671+
664672
t.RulerStorage, err = ruler.NewRuleStore(context.Background(), t.Cfg.RulerStorage, t.OverridesConfig, rules.FileLoader{}, util_log.Logger, prometheus.DefaultRegisterer, t.Cfg.NameValidationScheme)
665673
return
666674
}

pkg/cortex/modules_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"testing"
1111

1212
"github.com/gorilla/mux"
13+
"github.com/prometheus/prometheus/promql/parser"
1314
prom_storage "github.com/prometheus/prometheus/storage"
1415
"github.com/stretchr/testify/assert"
1516
"github.com/stretchr/testify/require"
@@ -169,6 +170,68 @@ func (p *myPusher) Push(ctx context.Context, req *cortexpb.WriteRequest) (*corte
169170
return nil, nil
170171
}
171172

173+
func TestCortex_InitRulerStorage_RegistersXFunctions(t *testing.T) {
174+
tests := map[string]struct {
175+
enableXFunctions bool
176+
expectRegistered bool
177+
}{
178+
"should register xfunctions when EnableXFunctions is true": {
179+
enableXFunctions: true,
180+
expectRegistered: true,
181+
},
182+
"should not register xfunctions when EnableXFunctions is false": {
183+
enableXFunctions: false,
184+
expectRegistered: false,
185+
},
186+
}
187+
188+
for testName, testData := range tests {
189+
t.Run(testName, func(t *testing.T) {
190+
// Clean up global state after each test
191+
originalFunctions := make(map[string]*parser.Function, len(parser.Functions))
192+
for k, v := range parser.Functions {
193+
originalFunctions[k] = v
194+
}
195+
defer func() {
196+
// Restore original parser.Functions
197+
for k := range parser.Functions {
198+
if _, ok := originalFunctions[k]; !ok {
199+
delete(parser.Functions, k)
200+
}
201+
}
202+
}()
203+
204+
cfg := newDefaultConfig()
205+
cfg.Target = []string{"ruler"}
206+
cfg.RulerStorage.Backend = "local"
207+
cfg.RulerStorage.Local.Directory = os.TempDir()
208+
cfg.Querier.ThanosEngine.EnableXFunctions = testData.enableXFunctions
209+
210+
cortex := &Cortex{
211+
Server: &server.Server{},
212+
Cfg: *cfg,
213+
}
214+
215+
_, err := cortex.initRulerStorage()
216+
require.NoError(t, err)
217+
218+
_, hasXincrease := parser.Functions["xincrease"]
219+
_, hasXrate := parser.Functions["xrate"]
220+
_, hasXdelta := parser.Functions["xdelta"]
221+
222+
if testData.expectRegistered {
223+
assert.True(t, hasXincrease, "xincrease should be registered")
224+
assert.True(t, hasXrate, "xrate should be registered")
225+
assert.True(t, hasXdelta, "xdelta should be registered")
226+
} else {
227+
assert.False(t, hasXincrease, "xincrease should not be registered")
228+
assert.False(t, hasXrate, "xrate should not be registered")
229+
assert.False(t, hasXdelta, "xdelta should not be registered")
230+
}
231+
})
232+
}
233+
}
234+
172235
type myQueryable struct{}
173236

174237
func (q *myQueryable) Querier(mint, maxt int64) (prom_storage.Querier, error) {

0 commit comments

Comments
 (0)