Merge pull request #12516 from vinted/convert_queryopts_to_interface

promql: convert QueryOpts to interface
This commit is contained in:
Julien Pivotto 2023-07-04 23:38:31 +02:00 committed by GitHub
commit 0186ec7873
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 36 deletions

View file

@ -130,11 +130,35 @@ type Query interface {
String() string String() string
} }
type QueryOpts struct { type PrometheusQueryOpts struct {
// Enables recording per-step statistics if the engine has it enabled as well. Disabled by default. // Enables recording per-step statistics if the engine has it enabled as well. Disabled by default.
EnablePerStepStats bool enablePerStepStats bool
// Lookback delta duration for this query. // Lookback delta duration for this query.
LookbackDelta time.Duration lookbackDelta time.Duration
}
var _ QueryOpts = &PrometheusQueryOpts{}
func NewPrometheusQueryOpts(enablePerStepStats bool, lookbackDelta time.Duration) QueryOpts {
return &PrometheusQueryOpts{
enablePerStepStats: enablePerStepStats,
lookbackDelta: lookbackDelta,
}
}
func (p *PrometheusQueryOpts) EnablePerStepStats() bool {
return p.enablePerStepStats
}
func (p *PrometheusQueryOpts) LookbackDelta() time.Duration {
return p.lookbackDelta
}
type QueryOpts interface {
// Enables recording per-step statistics if the engine has it enabled as well. Disabled by default.
EnablePerStepStats() bool
// Lookback delta duration for this query.
LookbackDelta() time.Duration
} }
// query implements the Query interface. // query implements the Query interface.
@ -408,7 +432,7 @@ func (ng *Engine) SetQueryLogger(l QueryLogger) {
} }
// NewInstantQuery returns an evaluation query for the given expression at the given time. // NewInstantQuery returns an evaluation query for the given expression at the given time.
func (ng *Engine) NewInstantQuery(ctx context.Context, q storage.Queryable, opts *QueryOpts, qs string, ts time.Time) (Query, error) { func (ng *Engine) NewInstantQuery(ctx context.Context, q storage.Queryable, opts QueryOpts, qs string, ts time.Time) (Query, error) {
pExpr, qry := ng.newQuery(q, qs, opts, ts, ts, 0) pExpr, qry := ng.newQuery(q, qs, opts, ts, ts, 0)
finishQueue, err := ng.queueActive(ctx, qry) finishQueue, err := ng.queueActive(ctx, qry)
if err != nil { if err != nil {
@ -429,7 +453,7 @@ func (ng *Engine) NewInstantQuery(ctx context.Context, q storage.Queryable, opts
// NewRangeQuery returns an evaluation query for the given time range and with // NewRangeQuery returns an evaluation query for the given time range and with
// the resolution set by the interval. // the resolution set by the interval.
func (ng *Engine) NewRangeQuery(ctx context.Context, q storage.Queryable, opts *QueryOpts, qs string, start, end time.Time, interval time.Duration) (Query, error) { func (ng *Engine) NewRangeQuery(ctx context.Context, q storage.Queryable, opts QueryOpts, qs string, start, end time.Time, interval time.Duration) (Query, error) {
pExpr, qry := ng.newQuery(q, qs, opts, start, end, interval) pExpr, qry := ng.newQuery(q, qs, opts, start, end, interval)
finishQueue, err := ng.queueActive(ctx, qry) finishQueue, err := ng.queueActive(ctx, qry)
if err != nil { if err != nil {
@ -451,13 +475,12 @@ func (ng *Engine) NewRangeQuery(ctx context.Context, q storage.Queryable, opts *
return qry, nil return qry, nil
} }
func (ng *Engine) newQuery(q storage.Queryable, qs string, opts *QueryOpts, start, end time.Time, interval time.Duration) (*parser.Expr, *query) { func (ng *Engine) newQuery(q storage.Queryable, qs string, opts QueryOpts, start, end time.Time, interval time.Duration) (*parser.Expr, *query) {
// Default to empty QueryOpts if not provided.
if opts == nil { if opts == nil {
opts = &QueryOpts{} opts = NewPrometheusQueryOpts(false, 0)
} }
lookbackDelta := opts.LookbackDelta lookbackDelta := opts.LookbackDelta()
if lookbackDelta <= 0 { if lookbackDelta <= 0 {
lookbackDelta = ng.lookbackDelta lookbackDelta = ng.lookbackDelta
} }
@ -473,7 +496,7 @@ func (ng *Engine) newQuery(q storage.Queryable, qs string, opts *QueryOpts, star
stmt: es, stmt: es,
ng: ng, ng: ng,
stats: stats.NewQueryTimers(), stats: stats.NewQueryTimers(),
sampleStats: stats.NewQuerySamples(ng.enablePerStepStats && opts.EnablePerStepStats), sampleStats: stats.NewQuerySamples(ng.enablePerStepStats && opts.EnablePerStepStats()),
queryable: q, queryable: q,
} }
return &es.Expr, qry return &es.Expr, qry

View file

@ -1198,7 +1198,7 @@ load 10s
origMaxSamples := engine.maxSamplesPerQuery origMaxSamples := engine.maxSamplesPerQuery
for _, c := range cases { for _, c := range cases {
t.Run(c.Query, func(t *testing.T) { t.Run(c.Query, func(t *testing.T) {
opts := &QueryOpts{EnablePerStepStats: true} opts := NewPrometheusQueryOpts(true, 0)
engine.maxSamplesPerQuery = origMaxSamples engine.maxSamplesPerQuery = origMaxSamples
runQuery := func(expErr error) *stats.Statistics { runQuery := func(expErr error) *stats.Statistics {
@ -4626,9 +4626,7 @@ metric 0 1 2
if c.engineLookback != 0 { if c.engineLookback != 0 {
eng.lookbackDelta = c.engineLookback eng.lookbackDelta = c.engineLookback
} }
opts := &QueryOpts{ opts := NewPrometheusQueryOpts(false, c.queryLookback)
LookbackDelta: c.queryLookback,
}
qry, err := eng.NewInstantQuery(test.context, test.Queryable(), opts, query, c.ts) qry, err := eng.NewInstantQuery(test.context, test.Queryable(), opts, query, c.ts)
require.NoError(t, err) require.NoError(t, err)

View file

@ -178,8 +178,13 @@ type TSDBAdminStats interface {
// QueryEngine defines the interface for the *promql.Engine, so it can be replaced, wrapped or mocked. // QueryEngine defines the interface for the *promql.Engine, so it can be replaced, wrapped or mocked.
type QueryEngine interface { type QueryEngine interface {
SetQueryLogger(l promql.QueryLogger) SetQueryLogger(l promql.QueryLogger)
NewInstantQuery(ctx context.Context, q storage.Queryable, opts *promql.QueryOpts, qs string, ts time.Time) (promql.Query, error) NewInstantQuery(ctx context.Context, q storage.Queryable, opts promql.QueryOpts, qs string, ts time.Time) (promql.Query, error)
NewRangeQuery(ctx context.Context, q storage.Queryable, opts *promql.QueryOpts, qs string, start, end time.Time, interval time.Duration) (promql.Query, error) NewRangeQuery(ctx context.Context, q storage.Queryable, opts promql.QueryOpts, qs string, start, end time.Time, interval time.Duration) (promql.Query, error)
}
type QueryOpts interface {
EnablePerStepStats() bool
LookbackDelta() time.Duration
} }
// API can register a set of endpoints in a router and handle // API can register a set of endpoints in a router and handle
@ -462,18 +467,18 @@ func (api *API) formatQuery(r *http.Request) (result apiFuncResult) {
return apiFuncResult{expr.Pretty(0), nil, nil, nil} return apiFuncResult{expr.Pretty(0), nil, nil, nil}
} }
func extractQueryOpts(r *http.Request) (*promql.QueryOpts, error) { func extractQueryOpts(r *http.Request) (promql.QueryOpts, error) {
opts := &promql.QueryOpts{ var duration time.Duration
EnablePerStepStats: r.FormValue("stats") == "all",
}
if strDuration := r.FormValue("lookback_delta"); strDuration != "" { if strDuration := r.FormValue("lookback_delta"); strDuration != "" {
duration, err := parseDuration(strDuration) parsedDuration, err := parseDuration(strDuration)
if err != nil { if err != nil {
return nil, fmt.Errorf("error parsing lookback delta duration: %w", err) return nil, fmt.Errorf("error parsing lookback delta duration: %w", err)
} }
opts.LookbackDelta = duration duration = parsedDuration
} }
return opts, nil
return promql.NewPrometheusQueryOpts(r.FormValue("stats") == "all", duration), nil
} }
func (api *API) queryRange(r *http.Request) (result apiFuncResult) { func (api *API) queryRange(r *http.Request) (result apiFuncResult) {

View file

@ -3627,7 +3627,7 @@ func TestExtractQueryOpts(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
form url.Values form url.Values
expect *promql.QueryOpts expect promql.QueryOpts
err error err error
}{ }{
{ {
@ -3635,9 +3635,8 @@ func TestExtractQueryOpts(t *testing.T) {
form: url.Values{ form: url.Values{
"stats": []string{"all"}, "stats": []string{"all"},
}, },
expect: &promql.QueryOpts{ expect: promql.NewPrometheusQueryOpts(true, 0),
EnablePerStepStats: true,
},
err: nil, err: nil,
}, },
{ {
@ -3645,10 +3644,8 @@ func TestExtractQueryOpts(t *testing.T) {
form: url.Values{ form: url.Values{
"stats": []string{"none"}, "stats": []string{"none"},
}, },
expect: &promql.QueryOpts{ expect: promql.NewPrometheusQueryOpts(false, 0),
EnablePerStepStats: false, err: nil,
},
err: nil,
}, },
{ {
name: "with lookback delta", name: "with lookback delta",
@ -3656,11 +3653,8 @@ func TestExtractQueryOpts(t *testing.T) {
"stats": []string{"all"}, "stats": []string{"all"},
"lookback_delta": []string{"30s"}, "lookback_delta": []string{"30s"},
}, },
expect: &promql.QueryOpts{ expect: promql.NewPrometheusQueryOpts(true, 30*time.Second),
EnablePerStepStats: true, err: nil,
LookbackDelta: 30 * time.Second,
},
err: nil,
}, },
{ {
name: "with invalid lookback delta", name: "with invalid lookback delta",