From 6a5b1fbf0c49ce6ac646c5f5a843b9c2fe224f29 Mon Sep 17 00:00:00 2001 From: Pedro Tanaka Date: Thu, 28 Dec 2023 10:56:42 +0100 Subject: [PATCH 01/10] Adding new parameter for extended functions in querier Signed-off-by: Pedro Tanaka --- cmd/thanos/query.go | 83 ++++------------------------------------ pkg/api/query/v1.go | 9 ++--- pkg/api/query/v1_test.go | 8 ++-- 3 files changed, 16 insertions(+), 84 deletions(-) diff --git a/cmd/thanos/query.go b/cmd/thanos/query.go index 82f04f67d1..d60f0cbf1b 100644 --- a/cmd/thanos/query.go +++ b/cmd/thanos/query.go @@ -102,7 +102,7 @@ func registerQuery(app *extkingpin.App) { defaultEngine := cmd.Flag("query.promql-engine", "Default PromQL engine to use.").Default(string(apiv1.PromqlEnginePrometheus)). Enum(string(apiv1.PromqlEnginePrometheus), string(apiv1.PromqlEngineThanos)) - + extendedFunctionsEnabled := cmd.Flag("query.xfunctions-enabled", "Whether to enable using extended functions.").Default("false").Bool() promqlQueryMode := cmd.Flag("query.mode", "PromQL query mode. One of: local, distributed."). Hidden(). Default(string(queryModeLocal)). @@ -342,6 +342,7 @@ func registerQuery(app *extkingpin.App) { *queryTelemetrySeriesQuantiles, *defaultEngine, storeRateLimits, + extendedFunctionsEnabled, queryMode(*promqlQueryMode), *tenantHeader, *defaultTenant, @@ -352,80 +353,7 @@ func registerQuery(app *extkingpin.App) { // runQuery starts a server that exposes PromQL Query API. It is responsible for querying configured // store nodes, merging and duplicating the data to satisfy user query. -func runQuery( - g *run.Group, - logger log.Logger, - debugLogging bool, - reg *prometheus.Registry, - tracer opentracing.Tracer, - httpLogOpts []logging.Option, - grpcLogOpts []grpc_logging.Option, - tagOpts []tags.Option, - grpcServerConfig grpcConfig, - grpcCompression string, - secure bool, - skipVerify bool, - cert string, - key string, - caCert string, - serverName string, - httpBindAddr string, - httpTLSConfig string, - httpGracePeriod time.Duration, - webRoutePrefix string, - webExternalPrefix string, - webPrefixHeaderName string, - maxConcurrentQueries int, - maxConcurrentSelects int, - defaultRangeQueryStep time.Duration, - queryTimeout time.Duration, - lookbackDelta time.Duration, - dynamicLookbackDelta bool, - defaultEvaluationInterval time.Duration, - storeResponseTimeout time.Duration, - queryConnMetricLabels []string, - queryReplicaLabels []string, - selectorLset labels.Labels, - flagsMap map[string]string, - endpointAddrs []string, - endpointGroupAddrs []string, - storeAddrs []string, - ruleAddrs []string, - targetAddrs []string, - metadataAddrs []string, - exemplarAddrs []string, - enableAutodownsampling bool, - enableQueryPartialResponse bool, - enableRulePartialResponse bool, - enableTargetPartialResponse bool, - enableMetricMetadataPartialResponse bool, - enableExemplarPartialResponse bool, - activeQueryDir string, - fileSD *file.Discovery, - dnsSDInterval time.Duration, - dnsSDResolver string, - unhealthyStoreTimeout time.Duration, - endpointInfoTimeout time.Duration, - instantDefaultMaxSourceResolution time.Duration, - defaultMetadataTimeRange time.Duration, - strictStores []string, - strictEndpoints []string, - strictEndpointGroups []string, - disableCORS bool, - enableQueryPushdown bool, - alertQueryURL string, - grpcProxyStrategy string, - comp component.Component, - queryTelemetryDurationQuantiles []float64, - queryTelemetrySamplesQuantiles []float64, - queryTelemetrySeriesQuantiles []float64, - defaultEngine string, - storeRateLimits store.SeriesSelectLimits, - queryMode queryMode, - tenantHeader string, - defaultTenant string, - tenantCertField string, -) error { +func runQuery(g *run.Group, logger log.Logger, debugLogging bool, reg *prometheus.Registry, tracer opentracing.Tracer, httpLogOpts []logging.Option, grpcLogOpts []grpc_logging.Option, tagOpts []tags.Option, grpcServerConfig grpcConfig, grpcCompression string, secure bool, skipVerify bool, cert string, key string, caCert string, serverName string, httpBindAddr string, httpTLSConfig string, httpGracePeriod time.Duration, webRoutePrefix string, webExternalPrefix string, webPrefixHeaderName string, maxConcurrentQueries int, maxConcurrentSelects int, defaultRangeQueryStep time.Duration, queryTimeout time.Duration, lookbackDelta time.Duration, dynamicLookbackDelta bool, defaultEvaluationInterval time.Duration, storeResponseTimeout time.Duration, queryConnMetricLabels []string, queryReplicaLabels []string, selectorLset labels.Labels, flagsMap map[string]string, endpointAddrs []string, endpointGroupAddrs []string, storeAddrs []string, ruleAddrs []string, targetAddrs []string, metadataAddrs []string, exemplarAddrs []string, enableAutodownsampling bool, enableQueryPartialResponse bool, enableRulePartialResponse bool, enableTargetPartialResponse bool, enableMetricMetadataPartialResponse bool, enableExemplarPartialResponse bool, activeQueryDir string, fileSD *file.Discovery, dnsSDInterval time.Duration, dnsSDResolver string, unhealthyStoreTimeout time.Duration, endpointInfoTimeout time.Duration, instantDefaultMaxSourceResolution time.Duration, defaultMetadataTimeRange time.Duration, strictStores []string, strictEndpoints []string, strictEndpointGroups []string, disableCORS bool, enableQueryPushdown bool, alertQueryURL string, grpcProxyStrategy string, comp component.Component, queryTelemetryDurationQuantiles []float64, queryTelemetrySamplesQuantiles []float64, queryTelemetrySeriesQuantiles []float64, defaultEngine string, storeRateLimits store.SeriesSelectLimits, extendedFunctionsEnabled *bool, queryMode queryMode, tenantHeader string, defaultTenant string, tenantCertField string) error { if alertQueryURL == "" { lastColon := strings.LastIndex(httpBindAddr, ":") if lastColon != -1 { @@ -649,9 +577,14 @@ func runQuery( }) } + enableXFunctions := false + if extendedFunctionsEnabled != nil && *extendedFunctionsEnabled { + enableXFunctions = true + } engineFactory := apiv1.NewQueryEngineFactory( engineOpts, remoteEngineEndpoints, + enableXFunctions, ) lookbackDeltaCreator := LookbackDeltaFactory(engineOpts, dynamicLookbackDelta) diff --git a/pkg/api/query/v1.go b/pkg/api/query/v1.go index 9f654b549b..3939aeb0ba 100644 --- a/pkg/api/query/v1.go +++ b/pkg/api/query/v1.go @@ -99,6 +99,7 @@ type QueryEngineFactory struct { createThanosEngine sync.Once thanosEngine v1.QueryEngine + enableXFunctions bool } func (f *QueryEngineFactory) GetPrometheusEngine() v1.QueryEngine { @@ -118,7 +119,7 @@ func (f *QueryEngineFactory) GetThanosEngine() v1.QueryEngine { return } if f.remoteEngineEndpoints == nil { - f.thanosEngine = engine.New(engine.Opts{EngineOpts: f.engineOpts, Engine: f.GetPrometheusEngine(), EnableAnalysis: true}) + f.thanosEngine = engine.New(engine.Opts{EngineOpts: f.engineOpts, Engine: f.GetPrometheusEngine(), EnableAnalysis: true, EnableXFunctions: f.enableXFunctions}) } else { f.thanosEngine = engine.NewDistributedEngine(engine.Opts{EngineOpts: f.engineOpts, Engine: f.GetPrometheusEngine(), EnableAnalysis: true}, f.remoteEngineEndpoints) } @@ -127,13 +128,11 @@ func (f *QueryEngineFactory) GetThanosEngine() v1.QueryEngine { return f.thanosEngine } -func NewQueryEngineFactory( - engineOpts promql.EngineOpts, - remoteEngineEndpoints promqlapi.RemoteEndpoints, -) *QueryEngineFactory { +func NewQueryEngineFactory(engineOpts promql.EngineOpts, remoteEngineEndpoints promqlapi.RemoteEndpoints, enableExtendedFunctions bool) *QueryEngineFactory { return &QueryEngineFactory{ engineOpts: engineOpts, remoteEngineEndpoints: remoteEngineEndpoints, + enableXFunctions: enableExtendedFunctions, } } diff --git a/pkg/api/query/v1_test.go b/pkg/api/query/v1_test.go index 37195fb6bb..ef119bfa19 100644 --- a/pkg/api/query/v1_test.go +++ b/pkg/api/query/v1_test.go @@ -190,7 +190,7 @@ func TestQueryEndpoints(t *testing.T) { Reg: nil, MaxSamples: 10000, Timeout: timeout, - }, nil) + }, nil, false) api := &QueryAPI{ baseAPI: &baseAPI.BaseAPI{ Now: func() time.Time { return now }, @@ -643,7 +643,7 @@ func TestQueryExplainEndpoints(t *testing.T) { Reg: nil, MaxSamples: 10000, Timeout: timeout, - }, nil) + }, nil, false) api := &QueryAPI{ baseAPI: &baseAPI.BaseAPI{ Now: func() time.Time { return now }, @@ -707,7 +707,7 @@ func TestQueryAnalyzeEndpoints(t *testing.T) { Reg: nil, MaxSamples: 10000, Timeout: timeout, - }, nil) + }, nil, false) api := &QueryAPI{ baseAPI: &baseAPI.BaseAPI{ Now: func() time.Time { return now }, @@ -881,7 +881,7 @@ func TestMetadataEndpoints(t *testing.T) { Reg: nil, MaxSamples: 10000, Timeout: timeout, - }, nil) + }, nil, false) api := &QueryAPI{ baseAPI: &baseAPI.BaseAPI{ Now: func() time.Time { return now }, From 28dd70f6e259e529864db41627ce604267643829 Mon Sep 17 00:00:00 2001 From: Pedro Tanaka Date: Tue, 2 Jan 2024 11:51:16 +0100 Subject: [PATCH 02/10] Adding new flag for QFE Signed-off-by: Pedro Tanaka --- cmd/thanos/query_frontend.go | 11 +++++++++++ pkg/queryfrontend/config.go | 1 + 2 files changed, 12 insertions(+) diff --git a/cmd/thanos/query_frontend.go b/cmd/thanos/query_frontend.go index 9059288cdf..80b8f2fc43 100644 --- a/cmd/thanos/query_frontend.go +++ b/cmd/thanos/query_frontend.go @@ -16,6 +16,8 @@ import ( "github.com/opentracing/opentracing-go" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/prometheus/promql/parser" + "github.com/thanos-io/promql-engine/execution/parse" "github.com/weaveworks/common/user" "gopkg.in/yaml.v2" @@ -92,6 +94,9 @@ func registerQueryFrontend(app *extkingpin.App) { cmd.Flag("query-range.max-retries-per-request", "Maximum number of retries for a single query range request; beyond this, the downstream error is returned."). Default("5").IntVar(&cfg.QueryRangeConfig.MaxRetries) + cmd.Flag("query-frontend.enable-x-functions", "Enable experimental x- functions in query-frontend. --no-query-frontend.enable-x-functions for disabling."). + Default("false").BoolVar(&cfg.EnableXFunctions) + cmd.Flag("query-range.max-query-length", "Limit the query time range (end - start time) in the query-frontend, 0 disables it."). Default("0").DurationVar((*time.Duration)(&cfg.QueryRangeConfig.Limits.MaxQueryLength)) @@ -285,6 +290,12 @@ func runQueryFrontend( return errors.Wrap(err, "error validating the config") } + if cfg.EnableXFunctions { + parser.Functions["xrate"] = parse.XFunctions["xrate"] + parser.Functions["xincrease"] = parse.XFunctions["xincrease"] + parser.Functions["xdelta"] = parse.XFunctions["xdelta"] + } + tripperWare, err := queryfrontend.NewTripperware(cfg.Config, reg, logger) if err != nil { return errors.Wrap(err, "setup tripperwares") diff --git a/pkg/queryfrontend/config.go b/pkg/queryfrontend/config.go index 4b915764c5..176052bd33 100644 --- a/pkg/queryfrontend/config.go +++ b/pkg/queryfrontend/config.go @@ -209,6 +209,7 @@ type Config struct { TenantHeader string DefaultTenant string TenantCertField string + EnableXFunctions bool } // QueryRangeConfig holds the config for query range tripperware. From b3bbcb3733188ebbe75065ff32b2c0ee10ab069f Mon Sep 17 00:00:00 2001 From: Pedro Tanaka Date: Tue, 2 Jan 2024 12:09:19 +0100 Subject: [PATCH 03/10] improve argument passing in query side Signed-off-by: Pedro Tanaka --- cmd/thanos/query.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/cmd/thanos/query.go b/cmd/thanos/query.go index d60f0cbf1b..a5798782da 100644 --- a/cmd/thanos/query.go +++ b/cmd/thanos/query.go @@ -102,7 +102,7 @@ func registerQuery(app *extkingpin.App) { defaultEngine := cmd.Flag("query.promql-engine", "Default PromQL engine to use.").Default(string(apiv1.PromqlEnginePrometheus)). Enum(string(apiv1.PromqlEnginePrometheus), string(apiv1.PromqlEngineThanos)) - extendedFunctionsEnabled := cmd.Flag("query.xfunctions-enabled", "Whether to enable using extended functions.").Default("false").Bool() + extendedFunctionsEnabled := cmd.Flag("query.xfunctions-enabled", "Whether to enable extended rate functions (xrate, xincrease and xdelta).").Default("false").Bool() promqlQueryMode := cmd.Flag("query.mode", "PromQL query mode. One of: local, distributed."). Hidden(). Default(string(queryModeLocal)). @@ -342,7 +342,7 @@ func registerQuery(app *extkingpin.App) { *queryTelemetrySeriesQuantiles, *defaultEngine, storeRateLimits, - extendedFunctionsEnabled, + *extendedFunctionsEnabled, queryMode(*promqlQueryMode), *tenantHeader, *defaultTenant, @@ -353,7 +353,7 @@ func registerQuery(app *extkingpin.App) { // runQuery starts a server that exposes PromQL Query API. It is responsible for querying configured // store nodes, merging and duplicating the data to satisfy user query. -func runQuery(g *run.Group, logger log.Logger, debugLogging bool, reg *prometheus.Registry, tracer opentracing.Tracer, httpLogOpts []logging.Option, grpcLogOpts []grpc_logging.Option, tagOpts []tags.Option, grpcServerConfig grpcConfig, grpcCompression string, secure bool, skipVerify bool, cert string, key string, caCert string, serverName string, httpBindAddr string, httpTLSConfig string, httpGracePeriod time.Duration, webRoutePrefix string, webExternalPrefix string, webPrefixHeaderName string, maxConcurrentQueries int, maxConcurrentSelects int, defaultRangeQueryStep time.Duration, queryTimeout time.Duration, lookbackDelta time.Duration, dynamicLookbackDelta bool, defaultEvaluationInterval time.Duration, storeResponseTimeout time.Duration, queryConnMetricLabels []string, queryReplicaLabels []string, selectorLset labels.Labels, flagsMap map[string]string, endpointAddrs []string, endpointGroupAddrs []string, storeAddrs []string, ruleAddrs []string, targetAddrs []string, metadataAddrs []string, exemplarAddrs []string, enableAutodownsampling bool, enableQueryPartialResponse bool, enableRulePartialResponse bool, enableTargetPartialResponse bool, enableMetricMetadataPartialResponse bool, enableExemplarPartialResponse bool, activeQueryDir string, fileSD *file.Discovery, dnsSDInterval time.Duration, dnsSDResolver string, unhealthyStoreTimeout time.Duration, endpointInfoTimeout time.Duration, instantDefaultMaxSourceResolution time.Duration, defaultMetadataTimeRange time.Duration, strictStores []string, strictEndpoints []string, strictEndpointGroups []string, disableCORS bool, enableQueryPushdown bool, alertQueryURL string, grpcProxyStrategy string, comp component.Component, queryTelemetryDurationQuantiles []float64, queryTelemetrySamplesQuantiles []float64, queryTelemetrySeriesQuantiles []float64, defaultEngine string, storeRateLimits store.SeriesSelectLimits, extendedFunctionsEnabled *bool, queryMode queryMode, tenantHeader string, defaultTenant string, tenantCertField string) error { +func runQuery(g *run.Group, logger log.Logger, debugLogging bool, reg *prometheus.Registry, tracer opentracing.Tracer, httpLogOpts []logging.Option, grpcLogOpts []grpc_logging.Option, tagOpts []tags.Option, grpcServerConfig grpcConfig, grpcCompression string, secure bool, skipVerify bool, cert string, key string, caCert string, serverName string, httpBindAddr string, httpTLSConfig string, httpGracePeriod time.Duration, webRoutePrefix string, webExternalPrefix string, webPrefixHeaderName string, maxConcurrentQueries int, maxConcurrentSelects int, defaultRangeQueryStep time.Duration, queryTimeout time.Duration, lookbackDelta time.Duration, dynamicLookbackDelta bool, defaultEvaluationInterval time.Duration, storeResponseTimeout time.Duration, queryConnMetricLabels []string, queryReplicaLabels []string, selectorLset labels.Labels, flagsMap map[string]string, endpointAddrs []string, endpointGroupAddrs []string, storeAddrs []string, ruleAddrs []string, targetAddrs []string, metadataAddrs []string, exemplarAddrs []string, enableAutodownsampling bool, enableQueryPartialResponse bool, enableRulePartialResponse bool, enableTargetPartialResponse bool, enableMetricMetadataPartialResponse bool, enableExemplarPartialResponse bool, activeQueryDir string, fileSD *file.Discovery, dnsSDInterval time.Duration, dnsSDResolver string, unhealthyStoreTimeout time.Duration, endpointInfoTimeout time.Duration, instantDefaultMaxSourceResolution time.Duration, defaultMetadataTimeRange time.Duration, strictStores []string, strictEndpoints []string, strictEndpointGroups []string, disableCORS bool, enableQueryPushdown bool, alertQueryURL string, grpcProxyStrategy string, comp component.Component, queryTelemetryDurationQuantiles []float64, queryTelemetrySamplesQuantiles []float64, queryTelemetrySeriesQuantiles []float64, defaultEngine string, storeRateLimits store.SeriesSelectLimits, extendedFunctionsEnabled bool, queryMode queryMode, tenantHeader string, defaultTenant string, tenantCertField string) error { if alertQueryURL == "" { lastColon := strings.LastIndex(httpBindAddr, ":") if lastColon != -1 { @@ -577,14 +577,10 @@ func runQuery(g *run.Group, logger log.Logger, debugLogging bool, reg *prometheu }) } - enableXFunctions := false - if extendedFunctionsEnabled != nil && *extendedFunctionsEnabled { - enableXFunctions = true - } engineFactory := apiv1.NewQueryEngineFactory( engineOpts, remoteEngineEndpoints, - enableXFunctions, + extendedFunctionsEnabled, ) lookbackDeltaCreator := LookbackDeltaFactory(engineOpts, dynamicLookbackDelta) From 498c5b58060a7da23d2ba1204824928d8df8c442 Mon Sep 17 00:00:00 2001 From: Pedro Tanaka Date: Tue, 2 Jan 2024 12:14:13 +0100 Subject: [PATCH 04/10] Adding changelog Signed-off-by: Pedro Tanaka --- CHANGELOG.md | 2 ++ cmd/thanos/query.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3077ca6ef..c0d7c80b70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ We use *breaking :warning:* to mark changes that are not backward compatible (re - [#6984](https://github.com/thanos-io/thanos/pull/6984) Store Gateway: Added `--store.index-header-lazy-download-strategy` to specify how to lazily download index headers when lazy mmap is enabled. - [#6887](https://github.com/thanos-io/thanos/pull/6887) Query Frontend: *breaking :warning:* Add tenant label to relevant exported metrics. Note that this change may cause some pre-existing custom dashboard queries to be incorrect due to the added label. +- [#7028](https://github.com/thanos-io/thanos/pull/7028): Query Frontend: Add new `--query-frontend.enable-x-functions` flag to enable experimental extended functions. +- [#7028](https://github.com/thanos-io/thanos/pull/7028): Query: Add new `--query.enable-x-functions` flag to enable experimental extended functions. ### Changed diff --git a/cmd/thanos/query.go b/cmd/thanos/query.go index a5798782da..403160df3e 100644 --- a/cmd/thanos/query.go +++ b/cmd/thanos/query.go @@ -102,7 +102,7 @@ func registerQuery(app *extkingpin.App) { defaultEngine := cmd.Flag("query.promql-engine", "Default PromQL engine to use.").Default(string(apiv1.PromqlEnginePrometheus)). Enum(string(apiv1.PromqlEnginePrometheus), string(apiv1.PromqlEngineThanos)) - extendedFunctionsEnabled := cmd.Flag("query.xfunctions-enabled", "Whether to enable extended rate functions (xrate, xincrease and xdelta).").Default("false").Bool() + extendedFunctionsEnabled := cmd.Flag("query.enable-x-functions", "Whether to enable extended rate functions (xrate, xincrease and xdelta).").Default("false").Bool() promqlQueryMode := cmd.Flag("query.mode", "PromQL query mode. One of: local, distributed."). Hidden(). Default(string(queryModeLocal)). From 0ea90038bf58f34a97027587b59d1c53a97fc027 Mon Sep 17 00:00:00 2001 From: Pedro Tanaka Date: Tue, 2 Jan 2024 13:31:05 +0100 Subject: [PATCH 05/10] Adding e2e test for query Signed-off-by: Pedro Tanaka --- .dockerignore | 2 ++ cmd/thanos/query.go | 2 +- cmd/thanos/query_frontend.go | 6 ++--- test/e2e/e2ethanos/services.go | 18 +++++++++++--- test/e2e/query_test.go | 43 ++++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 7 deletions(-) diff --git a/.dockerignore b/.dockerignore index 1032778a1e..e187fe7f74 100644 --- a/.dockerignore +++ b/.dockerignore @@ -25,3 +25,5 @@ website/docs-pre-processed/ !website/data tmp/ + +.build/ diff --git a/cmd/thanos/query.go b/cmd/thanos/query.go index 403160df3e..3059eb592f 100644 --- a/cmd/thanos/query.go +++ b/cmd/thanos/query.go @@ -102,7 +102,7 @@ func registerQuery(app *extkingpin.App) { defaultEngine := cmd.Flag("query.promql-engine", "Default PromQL engine to use.").Default(string(apiv1.PromqlEnginePrometheus)). Enum(string(apiv1.PromqlEnginePrometheus), string(apiv1.PromqlEngineThanos)) - extendedFunctionsEnabled := cmd.Flag("query.enable-x-functions", "Whether to enable extended rate functions (xrate, xincrease and xdelta).").Default("false").Bool() + extendedFunctionsEnabled := cmd.Flag("query.enable-x-functions", "Whether to enable extended rate functions (xrate, xincrease and xdelta). Only has effect when used with Thanos engine.").Default("false").Bool() promqlQueryMode := cmd.Flag("query.mode", "PromQL query mode. One of: local, distributed."). Hidden(). Default(string(queryModeLocal)). diff --git a/cmd/thanos/query_frontend.go b/cmd/thanos/query_frontend.go index 80b8f2fc43..5fa7cf3c5e 100644 --- a/cmd/thanos/query_frontend.go +++ b/cmd/thanos/query_frontend.go @@ -291,9 +291,9 @@ func runQueryFrontend( } if cfg.EnableXFunctions { - parser.Functions["xrate"] = parse.XFunctions["xrate"] - parser.Functions["xincrease"] = parse.XFunctions["xincrease"] - parser.Functions["xdelta"] = parse.XFunctions["xdelta"] + for fname, v := range parse.XFunctions { + parser.Functions[fname] = v + } } tripperWare, err := queryfrontend.NewTripperware(cfg.Config, reg, logger) diff --git a/test/e2e/e2ethanos/services.go b/test/e2e/e2ethanos/services.go index 73f6b68925..6cb319e5ae 100644 --- a/test/e2e/e2ethanos/services.go +++ b/test/e2e/e2ethanos/services.go @@ -29,6 +29,7 @@ import ( "github.com/thanos-io/objstore/exthttp" "github.com/thanos-io/thanos/pkg/alert" + apiv1 "github.com/thanos-io/thanos/pkg/api/query" "github.com/thanos-io/thanos/pkg/clientconfig" "github.com/thanos-io/thanos/pkg/queryfrontend" "github.com/thanos-io/thanos/pkg/receive" @@ -253,8 +254,9 @@ type QuerierBuilder struct { endpoints []string strictEndpoints []string - engine string - queryMode string + engine apiv1.PromqlEngineType + queryMode string + enableXFunctions bool replicaLabels []string tracingConfig string @@ -362,7 +364,7 @@ func (q *QuerierBuilder) WithDisablePartialResponses(disable bool) *QuerierBuild return q } -func (q *QuerierBuilder) WithEngine(engine string) *QuerierBuilder { +func (q *QuerierBuilder) WithEngine(engine apiv1.PromqlEngineType) *QuerierBuilder { q.engine = engine return q } @@ -372,6 +374,11 @@ func (q *QuerierBuilder) WithQueryMode(mode string) *QuerierBuilder { return q } +func (q *QuerierBuilder) WithEnableXFunctions(enable bool) *QuerierBuilder { + q.enableXFunctions = enable + return q +} + func (q *QuerierBuilder) WithEnvVars(envVars map[string]string) *QuerierBuilder { q.envVars = envVars return q @@ -410,6 +417,7 @@ func (q *QuerierBuilder) collectArgs() ([]string, error) { "--log.level": infoLogLevel, "--query.max-concurrent": "1", "--store.sd-interval": "5s", + "--query.promql-engine": string(q.engine), }) for _, repl := range q.replicaLabels { @@ -484,6 +492,10 @@ func (q *QuerierBuilder) collectArgs() ([]string, error) { for _, bucket := range q.telemetrySeriesQuantiles { args = append(args, "--query.telemetry.request-series-seconds-quantiles="+strconv.FormatFloat(bucket, 'f', -1, 64)) } + if q.enableXFunctions { + args = append(args, "--query.enable-x-functions") + } + return args, nil } diff --git a/test/e2e/query_test.go b/test/e2e/query_test.go index 5b9a120b90..1c64bf33f5 100644 --- a/test/e2e/query_test.go +++ b/test/e2e/query_test.go @@ -315,6 +315,49 @@ func TestQuery(t *testing.T) { }) } +func TestQueryWithExtendedFunctions(t *testing.T) { + t.Parallel() + + e, err := e2e.New(e2e.WithName("e2e-qry-xfunc")) + testutil.Ok(t, err) + t.Cleanup(e2ethanos.CleanScenario(t, e)) + + // create prom + sidecar + prom, sidecar := e2ethanos.NewPrometheusWithSidecar(e, "prom", e2ethanos.DefaultPromConfig("prom", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") + testutil.Ok(t, e2e.StartAndWaitReady(prom, sidecar)) + + // create querier + q := e2ethanos.NewQuerierBuilder(e, "1", sidecar.InternalEndpoint("grpc")).WithEngine("thanos").WithEnableXFunctions(true).Init() + testutil.Ok(t, e2e.StartAndWaitReady(q)) + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) + t.Cleanup(cancel) + + // send series to prom + samples := []seriesWithLabels{ + {intLabels: labels.FromStrings("__name__", "my_fake_metric", "a", "1", "b", "1", "instance", "1")}, + {intLabels: labels.FromStrings("__name__", "my_fake_metric", "a", "1", "b", "2", "instance", "1")}, + {intLabels: labels.FromStrings("__name__", "my_fake_metric", "a", "2", "b", "1", "instance", "1")}, + {intLabels: labels.FromStrings("__name__", "my_fake_metric", "a", "2", "b", "2", "instance", "1")}, + } + testutil.Ok(t, remoteWriteSeriesWithLabels(ctx, prom, samples)) + + // query + queryAndAssertSeries(t, ctx, q.Endpoint("http"), func() string { + return `xrate(my_fake_metric{a="1", b="1"}[1m])` + }, time.Now, promclient.QueryOptions{ + Deduplicate: false, + }, []model.Metric{ + { + "a": "1", + "b": "1", + "instance": "1", + "prometheus": "prom", + "replica": "0", + }, + }) +} + func TestQueryExternalPrefixWithoutReverseProxy(t *testing.T) { t.Parallel() From 2cd0d50840416d31718216f91d3770b26a3c3f54 Mon Sep 17 00:00:00 2001 From: Pedro Tanaka Date: Tue, 2 Jan 2024 13:33:41 +0100 Subject: [PATCH 06/10] undoing uneeded changes Signed-off-by: Pedro Tanaka --- cmd/thanos/query.go | 76 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/cmd/thanos/query.go b/cmd/thanos/query.go index 3059eb592f..ce6adde354 100644 --- a/cmd/thanos/query.go +++ b/cmd/thanos/query.go @@ -353,7 +353,81 @@ func registerQuery(app *extkingpin.App) { // runQuery starts a server that exposes PromQL Query API. It is responsible for querying configured // store nodes, merging and duplicating the data to satisfy user query. -func runQuery(g *run.Group, logger log.Logger, debugLogging bool, reg *prometheus.Registry, tracer opentracing.Tracer, httpLogOpts []logging.Option, grpcLogOpts []grpc_logging.Option, tagOpts []tags.Option, grpcServerConfig grpcConfig, grpcCompression string, secure bool, skipVerify bool, cert string, key string, caCert string, serverName string, httpBindAddr string, httpTLSConfig string, httpGracePeriod time.Duration, webRoutePrefix string, webExternalPrefix string, webPrefixHeaderName string, maxConcurrentQueries int, maxConcurrentSelects int, defaultRangeQueryStep time.Duration, queryTimeout time.Duration, lookbackDelta time.Duration, dynamicLookbackDelta bool, defaultEvaluationInterval time.Duration, storeResponseTimeout time.Duration, queryConnMetricLabels []string, queryReplicaLabels []string, selectorLset labels.Labels, flagsMap map[string]string, endpointAddrs []string, endpointGroupAddrs []string, storeAddrs []string, ruleAddrs []string, targetAddrs []string, metadataAddrs []string, exemplarAddrs []string, enableAutodownsampling bool, enableQueryPartialResponse bool, enableRulePartialResponse bool, enableTargetPartialResponse bool, enableMetricMetadataPartialResponse bool, enableExemplarPartialResponse bool, activeQueryDir string, fileSD *file.Discovery, dnsSDInterval time.Duration, dnsSDResolver string, unhealthyStoreTimeout time.Duration, endpointInfoTimeout time.Duration, instantDefaultMaxSourceResolution time.Duration, defaultMetadataTimeRange time.Duration, strictStores []string, strictEndpoints []string, strictEndpointGroups []string, disableCORS bool, enableQueryPushdown bool, alertQueryURL string, grpcProxyStrategy string, comp component.Component, queryTelemetryDurationQuantiles []float64, queryTelemetrySamplesQuantiles []float64, queryTelemetrySeriesQuantiles []float64, defaultEngine string, storeRateLimits store.SeriesSelectLimits, extendedFunctionsEnabled bool, queryMode queryMode, tenantHeader string, defaultTenant string, tenantCertField string) error { +func runQuery( + g *run.Group, + logger log.Logger, + debugLogging bool, + reg *prometheus.Registry, + tracer opentracing.Tracer, + httpLogOpts []logging.Option, + grpcLogOpts []grpc_logging.Option, + tagOpts []tags.Option, + grpcServerConfig grpcConfig, + grpcCompression string, + secure bool, + skipVerify bool, + cert string, + key string, + caCert string, + serverName string, + httpBindAddr string, + httpTLSConfig string, + httpGracePeriod time.Duration, + webRoutePrefix string, + webExternalPrefix string, + webPrefixHeaderName string, + maxConcurrentQueries int, + maxConcurrentSelects int, + defaultRangeQueryStep time.Duration, + queryTimeout time.Duration, + lookbackDelta time.Duration, + dynamicLookbackDelta bool, + defaultEvaluationInterval time.Duration, + storeResponseTimeout time.Duration, + queryConnMetricLabels []string, + queryReplicaLabels []string, + selectorLset labels.Labels, + flagsMap map[string]string, + endpointAddrs []string, + endpointGroupAddrs []string, + storeAddrs []string, + ruleAddrs []string, + targetAddrs []string, + metadataAddrs []string, + exemplarAddrs []string, + enableAutodownsampling bool, + enableQueryPartialResponse bool, + enableRulePartialResponse bool, + enableTargetPartialResponse bool, + enableMetricMetadataPartialResponse bool, + enableExemplarPartialResponse bool, + activeQueryDir string, + fileSD *file.Discovery, + dnsSDInterval time.Duration, + dnsSDResolver string, + unhealthyStoreTimeout time.Duration, + endpointInfoTimeout time.Duration, + instantDefaultMaxSourceResolution time.Duration, + defaultMetadataTimeRange time.Duration, + strictStores []string, + strictEndpoints []string, + strictEndpointGroups []string, + disableCORS bool, + enableQueryPushdown bool, + alertQueryURL string, + grpcProxyStrategy string, + comp component.Component, + queryTelemetryDurationQuantiles []float64, + queryTelemetrySamplesQuantiles []float64, + queryTelemetrySeriesQuantiles []float64, + defaultEngine string, + storeRateLimits store.SeriesSelectLimits, + extendedFunctionsEnabled bool, + queryMode queryMode, + tenantHeader string, + defaultTenant string, + tenantCertField string, +) error { if alertQueryURL == "" { lastColon := strings.LastIndex(httpBindAddr, ":") if lastColon != -1 { From f53a02b8a1ea5f1271e104f564d75f7de5da4c48 Mon Sep 17 00:00:00 2001 From: Pedro Tanaka Date: Tue, 2 Jan 2024 13:43:58 +0100 Subject: [PATCH 07/10] fixing docs Signed-off-by: Pedro Tanaka --- docs/components/query-frontend.md | 5 +++++ docs/components/query.md | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/docs/components/query-frontend.md b/docs/components/query-frontend.md index a6fde2ba77..e374f19ec1 100644 --- a/docs/components/query-frontend.md +++ b/docs/components/query-frontend.md @@ -252,6 +252,11 @@ Flags: --query-frontend.downstream-url="http://localhost:9090" URL of downstream Prometheus Query compatible API. + --query-frontend.enable-x-functions + Enable experimental x- + functions in query-frontend. + --no-query-frontend.enable-x-functions for + disabling. --query-frontend.forward-header= ... List of headers forwarded by the query-frontend to downstream queriers, default is empty diff --git a/docs/components/query.md b/docs/components/query.md index 2c4f473464..677f0b8a0a 100644 --- a/docs/components/query.md +++ b/docs/components/query.md @@ -363,6 +363,10 @@ Flags: --query.default-tenant-id="default-tenant" Default tenant ID to use if tenant header is not present + --query.enable-x-functions + Whether to enable extended rate functions + (xrate, xincrease and xdelta). Only has effect + when used with Thanos engine. --query.lookback-delta=QUERY.LOOKBACK-DELTA The maximum lookback duration for retrieving metrics during expression evaluations. From 7ef4f780ae3289080bc0f3c78e7fef475ec44672 Mon Sep 17 00:00:00 2001 From: Pedro Tanaka Date: Tue, 2 Jan 2024 14:00:59 +0100 Subject: [PATCH 08/10] fixing e2e tests Signed-off-by: Pedro Tanaka --- test/e2e/e2ethanos/services.go | 1 + 1 file changed, 1 insertion(+) diff --git a/test/e2e/e2ethanos/services.go b/test/e2e/e2ethanos/services.go index 6cb319e5ae..dd0ce286d0 100644 --- a/test/e2e/e2ethanos/services.go +++ b/test/e2e/e2ethanos/services.go @@ -280,6 +280,7 @@ func NewQuerierBuilder(e e2e.Environment, name string, storeAddresses ...string) storeAddresses: storeAddresses, image: DefaultImage(), replicaLabels: []string{replicaLabel}, + engine: apiv1.PromqlEnginePrometheus, } } From ac9f48c70643c181075eba909fab6646eae582b8 Mon Sep 17 00:00:00 2001 From: Pedro Tanaka Date: Tue, 2 Jan 2024 14:12:51 +0100 Subject: [PATCH 09/10] Fixing backward compat test Signed-off-by: Pedro Tanaka --- test/e2e/e2ethanos/services.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/e2e/e2ethanos/services.go b/test/e2e/e2ethanos/services.go index dd0ce286d0..4c435ccd88 100644 --- a/test/e2e/e2ethanos/services.go +++ b/test/e2e/e2ethanos/services.go @@ -280,7 +280,6 @@ func NewQuerierBuilder(e e2e.Environment, name string, storeAddresses ...string) storeAddresses: storeAddresses, image: DefaultImage(), replicaLabels: []string{replicaLabel}, - engine: apiv1.PromqlEnginePrometheus, } } @@ -418,7 +417,6 @@ func (q *QuerierBuilder) collectArgs() ([]string, error) { "--log.level": infoLogLevel, "--query.max-concurrent": "1", "--store.sd-interval": "5s", - "--query.promql-engine": string(q.engine), }) for _, repl := range q.replicaLabels { @@ -496,6 +494,9 @@ func (q *QuerierBuilder) collectArgs() ([]string, error) { if q.enableXFunctions { args = append(args, "--query.enable-x-functions") } + if q.engine != "" { + args = append(args, "--query.promql-engine="+string(q.engine)) + } return args, nil } From d099dab5570adf9d3ecdead6de8b22db34ebeca7 Mon Sep 17 00:00:00 2001 From: Pedro Tanaka Date: Wed, 3 Jan 2024 09:51:45 +0100 Subject: [PATCH 10/10] changes from CR Signed-off-by: Pedro Tanaka --- .dockerignore | 2 -- CHANGELOG.md | 3 +-- test/e2e/e2ethanos/services.go | 4 ++-- test/e2e/query_test.go | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.dockerignore b/.dockerignore index e187fe7f74..1032778a1e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -25,5 +25,3 @@ website/docs-pre-processed/ !website/data tmp/ - -.build/ diff --git a/CHANGELOG.md b/CHANGELOG.md index c0d7c80b70..0364a3c0ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,8 +27,7 @@ We use *breaking :warning:* to mark changes that are not backward compatible (re - [#6984](https://github.com/thanos-io/thanos/pull/6984) Store Gateway: Added `--store.index-header-lazy-download-strategy` to specify how to lazily download index headers when lazy mmap is enabled. - [#6887](https://github.com/thanos-io/thanos/pull/6887) Query Frontend: *breaking :warning:* Add tenant label to relevant exported metrics. Note that this change may cause some pre-existing custom dashboard queries to be incorrect due to the added label. -- [#7028](https://github.com/thanos-io/thanos/pull/7028): Query Frontend: Add new `--query-frontend.enable-x-functions` flag to enable experimental extended functions. -- [#7028](https://github.com/thanos-io/thanos/pull/7028): Query: Add new `--query.enable-x-functions` flag to enable experimental extended functions. +- [#7028](https://github.com/thanos-io/thanos/pull/7028) Query|Query Frontend: Add new `--query-frontend.enable-x-functions` flag to enable experimental extended functions. ### Changed diff --git a/test/e2e/e2ethanos/services.go b/test/e2e/e2ethanos/services.go index 4c435ccd88..7eaff47b40 100644 --- a/test/e2e/e2ethanos/services.go +++ b/test/e2e/e2ethanos/services.go @@ -374,8 +374,8 @@ func (q *QuerierBuilder) WithQueryMode(mode string) *QuerierBuilder { return q } -func (q *QuerierBuilder) WithEnableXFunctions(enable bool) *QuerierBuilder { - q.enableXFunctions = enable +func (q *QuerierBuilder) WithEnableXFunctions() *QuerierBuilder { + q.enableXFunctions = true return q } diff --git a/test/e2e/query_test.go b/test/e2e/query_test.go index 1c64bf33f5..81eda46f99 100644 --- a/test/e2e/query_test.go +++ b/test/e2e/query_test.go @@ -327,7 +327,7 @@ func TestQueryWithExtendedFunctions(t *testing.T) { testutil.Ok(t, e2e.StartAndWaitReady(prom, sidecar)) // create querier - q := e2ethanos.NewQuerierBuilder(e, "1", sidecar.InternalEndpoint("grpc")).WithEngine("thanos").WithEnableXFunctions(true).Init() + q := e2ethanos.NewQuerierBuilder(e, "1", sidecar.InternalEndpoint("grpc")).WithEngine("thanos").WithEnableXFunctions().Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)