diff --git a/pkg/tsdb/prometheus/models/query.go b/pkg/tsdb/prometheus/models/query.go index 3f5a282aadb..03cb044aea6 100644 --- a/pkg/tsdb/prometheus/models/query.go +++ b/pkg/tsdb/prometheus/models/query.go @@ -96,6 +96,7 @@ func Parse(query backend.DataQuery, dsScrapeInterval string, intervalCalculator query.Interval, calculatedMinStep, model.Interval, + dsScrapeInterval, timeRange, ) var rangeQuery, instantQuery bool @@ -227,12 +228,14 @@ func calculateRateInterval( // queryInterval Requested interval in milliseconds. This value may be overridden by MinStep in query options // calculatedMinStep Calculated final step value. It was calculated in calculatePrometheusInterval // requestedMinStep Requested minimum step value. QueryModel.interval +// dsScrapeInterval Data source scrape interval in the config // timeRange Requested time range for query func interpolateVariables( expr string, queryInterval time.Duration, calculatedMinStep time.Duration, requestedMinStep string, + dsScrapeInterval string, timeRange time.Duration, ) string { rangeMs := timeRange.Milliseconds() @@ -245,6 +248,9 @@ func interpolateVariables( if requestedMinStep == varInterval || requestedMinStep == varIntervalAlt { requestedMinStep = calculatedMinStep.String() } + if requestedMinStep == "" { + requestedMinStep = dsScrapeInterval + } rateInterval = calculateRateInterval(queryInterval, requestedMinStep) } diff --git a/pkg/tsdb/prometheus/models/query_test.go b/pkg/tsdb/prometheus/models/query_test.go index 5c86ab17e7b..6627f092715 100644 --- a/pkg/tsdb/prometheus/models/query_test.go +++ b/pkg/tsdb/prometheus/models/query_test.go @@ -571,7 +571,7 @@ func TestRateInterval(t *testing.T) { }, }, want: &models.Query{ - Expr: "rate(rpc_durations_seconds_count[2m30s])", + Expr: "rate(rpc_durations_seconds_count[2m0s])", Step: time.Second * 30, }, }, @@ -637,6 +637,75 @@ func TestRateInterval(t *testing.T) { require.Equal(t, tt.want.Step, res.Step) }) } + + t.Run("minStep is auto and ds scrape interval 30s and time range 1 hour", func(t *testing.T) { + query := backend.DataQuery{ + RefID: "G", + QueryType: "", + MaxDataPoints: 1613, + Interval: 30 * time.Second, + TimeRange: backend.TimeRange{ + From: now, + To: now.Add(1 * time.Hour), + }, + JSON: []byte(`{ + "datasource":{"type":"prometheus","uid":"zxS5e5W4k"}, + "datasourceId":38, + "editorMode":"code", + "exemplar":false, + "expr":"sum(rate(process_cpu_seconds_total[$__rate_interval]))", + "instant":false, + "interval":"", + "intervalMs":30000, + "key":"Q-f96b6729-c47a-4ea8-8f71-a79774cf9bd5-0", + "legendFormat":"__auto", + "maxDataPoints":1613, + "range":true, + "refId":"G", + "requestId":"1G", + "utcOffsetSec":3600 + }`), + } + res, err := models.Parse(query, "30s", intervalCalculator, false) + require.NoError(t, err) + require.Equal(t, "sum(rate(process_cpu_seconds_total[2m0s]))", res.Expr) + require.Equal(t, 30*time.Second, res.Step) + }) + + t.Run("minStep is auto and ds scrape interval 15s and time range 5 minutes", func(t *testing.T) { + query := backend.DataQuery{ + RefID: "A", + QueryType: "", + MaxDataPoints: 1055, + Interval: 15 * time.Second, + TimeRange: backend.TimeRange{ + From: now, + To: now.Add(5 * time.Minute), + }, + JSON: []byte(`{ + "datasource": { + "type": "prometheus", + "uid": "2z9d6ElGk" + }, + "editorMode": "code", + "expr": "sum(rate(cache_requests_total[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A", + "exemplar": false, + "requestId": "1A", + "utcOffsetSec": 0, + "interval": "", + "datasourceId": 508, + "intervalMs": 15000, + "maxDataPoints": 1055 + }`), + } + res, err := models.Parse(query, "15s", intervalCalculator, false) + require.NoError(t, err) + require.Equal(t, "sum(rate(cache_requests_total[1m0s]))", res.Expr) + require.Equal(t, 15*time.Second, res.Step) + }) } func mockQuery(expr string, interval string, intervalMs int64, timeRange *backend.TimeRange) backend.DataQuery { @@ -647,7 +716,7 @@ func mockQuery(expr string, interval string, intervalMs int64, timeRange *backen } } return backend.DataQuery{ - Interval: 2 * time.Minute, + Interval: time.Duration(intervalMs) * time.Millisecond, JSON: []byte(fmt.Sprintf(`{ "expr": "%s", "format": "time_series",