diff --git a/pkg/services/alerting/conditions/query.go b/pkg/services/alerting/conditions/query.go index a51b4874a91..d3100ca9c43 100644 --- a/pkg/services/alerting/conditions/query.go +++ b/pkg/services/alerting/conditions/query.go @@ -128,10 +128,7 @@ func calculateInterval(timeRange plugins.DataTimeRange, model *simplejson.Json, calc := interval.NewCalculator() - interval, err := calc.Calculate(timeRange, minInterval, "min") - if err != nil { - return time.Duration(0), err - } + interval := calc.Calculate(timeRange, minInterval) return interval.Value, nil } diff --git a/pkg/tsdb/cloudmonitoring/time_series_query.go b/pkg/tsdb/cloudmonitoring/time_series_query.go index 89275e21fff..86b9b6bfc88 100644 --- a/pkg/tsdb/cloudmonitoring/time_series_query.go +++ b/pkg/tsdb/cloudmonitoring/time_series_query.go @@ -45,11 +45,7 @@ func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) run(ctx context.Context, t return queryResult, cloudMonitoringResponse{}, "", nil } intervalCalculator := interval.NewCalculator(interval.CalculatorOptions{}) - interval, err := intervalCalculator.Calculate(*tsdbQuery.TimeRange, time.Duration(timeSeriesQuery.IntervalMS/1000)*time.Second, "min") - if err != nil { - queryResult.Error = err - return queryResult, cloudMonitoringResponse{}, "", nil - } + interval := intervalCalculator.Calculate(*tsdbQuery.TimeRange, time.Duration(timeSeriesQuery.IntervalMS/1000)*time.Second) timeFormat := "2006/01/02-15:04:05" timeSeriesQuery.Query += fmt.Sprintf(" | graph_period %s | within d'%s', d'%s'", interval.Text, from.UTC().Format(timeFormat), to.UTC().Format(timeFormat)) diff --git a/pkg/tsdb/elasticsearch/time_series_query.go b/pkg/tsdb/elasticsearch/time_series_query.go index 703bd0fe459..4b4927d54f3 100644 --- a/pkg/tsdb/elasticsearch/time_series_query.go +++ b/pkg/tsdb/elasticsearch/time_series_query.go @@ -70,12 +70,9 @@ func (e *timeSeriesQuery) processQuery(q *Query, ms *es.MultiSearchRequestBuilde if err != nil { return err } - intrvl, err := e.intervalCalculator.Calculate(e.dataQueries[0].TimeRange, minInterval, intervalv2.Min) - if err != nil { - return err - } + interval := e.intervalCalculator.Calculate(e.dataQueries[0].TimeRange, minInterval) - b := ms.Search(intrvl) + b := ms.Search(interval) b.Size(0) filters := b.Query().Bool().Filter() filters.AddDateRangeFilter(e.client.GetTimeField(), to, from, es.DateFormatEpochMS) diff --git a/pkg/tsdb/interval/interval.go b/pkg/tsdb/interval/interval.go index 71d97af68cf..ab271421dd0 100644 --- a/pkg/tsdb/interval/interval.go +++ b/pkg/tsdb/interval/interval.go @@ -29,7 +29,7 @@ type intervalCalculator struct { } type Calculator interface { - Calculate(timeRange plugins.DataTimeRange, interval time.Duration, intervalMode string) (Interval, error) + Calculate(timeRange plugins.DataTimeRange, interval time.Duration) Interval CalculateSafeInterval(timeRange plugins.DataTimeRange, resolution int64) Interval } @@ -55,29 +55,17 @@ func (i *Interval) Milliseconds() int64 { return i.Value.Nanoseconds() / int64(time.Millisecond) } -func (ic *intervalCalculator) Calculate(timerange plugins.DataTimeRange, interval time.Duration, intervalMode string) (Interval, error) { +func (ic *intervalCalculator) Calculate(timerange plugins.DataTimeRange, minInterval time.Duration) Interval { to := timerange.MustGetTo().UnixNano() from := timerange.MustGetFrom().UnixNano() calculatedInterval := time.Duration((to - from) / DefaultRes) - switch intervalMode { - case "min": - if calculatedInterval < interval { - return Interval{Text: FormatDuration(interval), Value: interval}, nil - } - case "max": - if calculatedInterval > interval { - return Interval{Text: FormatDuration(interval), Value: interval}, nil - } - case "exact": - return Interval{Text: FormatDuration(interval), Value: interval}, nil - - default: - return Interval{}, fmt.Errorf("unrecognized intervalMode: %v", intervalMode) + if calculatedInterval < minInterval { + return Interval{Text: FormatDuration(minInterval), Value: minInterval} } rounded := roundInterval(calculatedInterval) - return Interval{Text: FormatDuration(rounded), Value: rounded}, nil + return Interval{Text: FormatDuration(rounded), Value: rounded} } func (ic *intervalCalculator) CalculateSafeInterval(timerange plugins.DataTimeRange, safeRes int64) Interval { diff --git a/pkg/tsdb/interval/interval_test.go b/pkg/tsdb/interval/interval_test.go index c2c6fe8d90e..4f5501aeeb2 100644 --- a/pkg/tsdb/interval/interval_test.go +++ b/pkg/tsdb/interval/interval_test.go @@ -15,29 +15,19 @@ func TestIntervalCalculator_Calculate(t *testing.T) { calculator := NewCalculator(CalculatorOptions{}) testCases := []struct { - name string - timeRange plugins.DataTimeRange - intervalMode string - expected string + name string + timeRange plugins.DataTimeRange + expected string }{ - {"from 5m to now", plugins.NewDataTimeRange("5m", "now"), "min", "200ms"}, - {"from 5m to now", plugins.NewDataTimeRange("5m", "now"), "exact", "1ms"}, - {"from 5m to now", plugins.NewDataTimeRange("5m", "now"), "max", "1ms"}, - {"from 15m to now", plugins.NewDataTimeRange("15m", "now"), "min", "500ms"}, - {"from 15m to now", plugins.NewDataTimeRange("15m", "now"), "max", "1ms"}, - {"from 15m to now", plugins.NewDataTimeRange("15m", "now"), "exact", "1ms"}, - {"from 30m to now", plugins.NewDataTimeRange("30m", "now"), "min", "1s"}, - {"from 30m to now", plugins.NewDataTimeRange("30m", "now"), "max", "1ms"}, - {"from 30m to now", plugins.NewDataTimeRange("30m", "now"), "exact", "1ms"}, - {"from 24h to now", plugins.NewDataTimeRange("24h", "now"), "min", "1m"}, - {"from 24h to now", plugins.NewDataTimeRange("24h", "now"), "max", "1ms"}, - {"from 24h to now", plugins.NewDataTimeRange("24h", "now"), "exact", "1ms"}, + {"from 5m to now", plugins.NewDataTimeRange("5m", "now"), "200ms"}, + {"from 15m to now", plugins.NewDataTimeRange("15m", "now"), "500ms"}, + {"from 30m to now", plugins.NewDataTimeRange("30m", "now"), "1s"}, + {"from 1h to now", plugins.NewDataTimeRange("1h", "now"), "2s"}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - interval, err := calculator.Calculate(tc.timeRange, time.Millisecond*1, tc.intervalMode) - require.Nil(t, err) + interval := calculator.Calculate(tc.timeRange, time.Millisecond*1) assert.Equal(t, tc.expected, interval.Text) }) } diff --git a/pkg/tsdb/intervalv2/intervalv2.go b/pkg/tsdb/intervalv2/intervalv2.go index 5376684bcce..886c521e379 100644 --- a/pkg/tsdb/intervalv2/intervalv2.go +++ b/pkg/tsdb/intervalv2/intervalv2.go @@ -17,14 +17,6 @@ var ( day = time.Hour * 24 ) -type IntervalMode string - -const ( - Min IntervalMode = "min" - Max IntervalMode = "max" - Exact IntervalMode = "exact" -) - type Interval struct { Text string Value time.Duration @@ -35,7 +27,7 @@ type intervalCalculator struct { } type Calculator interface { - Calculate(timerange backend.TimeRange, minInterval time.Duration, intervalMode IntervalMode) (Interval, error) + Calculate(timerange backend.TimeRange, minInterval time.Duration) Interval CalculateSafeInterval(timerange backend.TimeRange, resolution int64) Interval } @@ -61,29 +53,18 @@ func (i *Interval) Milliseconds() int64 { return i.Value.Nanoseconds() / int64(time.Millisecond) } -func (ic *intervalCalculator) Calculate(timerange backend.TimeRange, intrvl time.Duration, intervalMode IntervalMode) (Interval, error) { +func (ic *intervalCalculator) Calculate(timerange backend.TimeRange, minInterval time.Duration) Interval { to := timerange.To.UnixNano() from := timerange.From.UnixNano() calculatedIntrvl := time.Duration((to - from) / defaultRes) - switch intervalMode { - case Min: - if calculatedIntrvl < intrvl { - return Interval{Text: interval.FormatDuration(intrvl), Value: intrvl}, nil - } - case Max: - if calculatedIntrvl > intrvl { - return Interval{Text: interval.FormatDuration(intrvl), Value: intrvl}, nil - } - case Exact: - return Interval{Text: interval.FormatDuration(intrvl), Value: intrvl}, nil - - default: - return Interval{}, fmt.Errorf("unrecognized intervalMode: %v", intervalMode) + if calculatedIntrvl < minInterval { + return Interval{Text: interval.FormatDuration(minInterval), Value: minInterval} } rounded := roundInterval(calculatedIntrvl) - return Interval{Text: interval.FormatDuration(rounded), Value: rounded}, nil + + return Interval{Text: interval.FormatDuration(rounded), Value: rounded} } func (ic *intervalCalculator) CalculateSafeInterval(timerange backend.TimeRange, safeRes int64) Interval { diff --git a/pkg/tsdb/intervalv2/calculator_test.go b/pkg/tsdb/intervalv2/intervalv2_test.go similarity index 73% rename from pkg/tsdb/intervalv2/calculator_test.go rename to pkg/tsdb/intervalv2/intervalv2_test.go index a1855e34aa5..a91bb28147e 100644 --- a/pkg/tsdb/intervalv2/calculator_test.go +++ b/pkg/tsdb/intervalv2/intervalv2_test.go @@ -7,7 +7,6 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana/pkg/models" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestIntervalCalculator_Calculate(t *testing.T) { @@ -16,29 +15,19 @@ func TestIntervalCalculator_Calculate(t *testing.T) { timeNow := time.Now() testCases := []struct { - name string - timeRange backend.TimeRange - intervalMode IntervalMode - expected string + name string + timeRange backend.TimeRange + expected string }{ - {"from 5m to now", backend.TimeRange{From: timeNow, To: timeNow.Add(5 * time.Minute)}, Min, "200ms"}, - {"from 5m to now", backend.TimeRange{From: timeNow, To: timeNow.Add(5 * time.Minute)}, Max, "1ms"}, - {"from 5m to now", backend.TimeRange{From: timeNow, To: timeNow.Add(5 * time.Minute)}, Exact, "1ms"}, - {"from 15m to now", backend.TimeRange{From: timeNow, To: timeNow.Add(15 * time.Minute)}, Min, "500ms"}, - {"from 15m to now", backend.TimeRange{From: timeNow, To: timeNow.Add(15 * time.Minute)}, Max, "1ms"}, - {"from 15m to now", backend.TimeRange{From: timeNow, To: timeNow.Add(15 * time.Minute)}, Exact, "1ms"}, - {"from 30m to now", backend.TimeRange{From: timeNow, To: timeNow.Add(30 * time.Minute)}, Min, "1s"}, - {"from 30m to now", backend.TimeRange{From: timeNow, To: timeNow.Add(30 * time.Minute)}, Max, "1ms"}, - {"from 30m to now", backend.TimeRange{From: timeNow, To: timeNow.Add(30 * time.Minute)}, Exact, "1ms"}, - {"from 1h to now", backend.TimeRange{From: timeNow, To: timeNow.Add(1440 * time.Minute)}, Min, "1m"}, - {"from 1h to now", backend.TimeRange{From: timeNow, To: timeNow.Add(1440 * time.Minute)}, Max, "1ms"}, - {"from 1h to now", backend.TimeRange{From: timeNow, To: timeNow.Add(1440 * time.Minute)}, Exact, "1ms"}, + {"from 5m to now", backend.TimeRange{From: timeNow, To: timeNow.Add(5 * time.Minute)}, "200ms"}, + {"from 15m to now", backend.TimeRange{From: timeNow, To: timeNow.Add(15 * time.Minute)}, "500ms"}, + {"from 30m to now", backend.TimeRange{From: timeNow, To: timeNow.Add(30 * time.Minute)}, "1s"}, + {"from 1h to now", backend.TimeRange{From: timeNow, To: timeNow.Add(60 * time.Minute)}, "2s"}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - interval, err := calculator.Calculate(tc.timeRange, time.Millisecond*1, tc.intervalMode) - require.Nil(t, err) + interval := calculator.Calculate(tc.timeRange, time.Millisecond*1) assert.Equal(t, tc.expected, interval.Text) }) } diff --git a/pkg/tsdb/loki/loki.go b/pkg/tsdb/loki/loki.go index 39f722ca007..edb717deea1 100644 --- a/pkg/tsdb/loki/loki.go +++ b/pkg/tsdb/loki/loki.go @@ -200,10 +200,7 @@ func (s *Service) parseQuery(dsInfo *datasourceInfo, queryContext *backend.Query return nil, fmt.Errorf("failed to parse Interval: %v", err) } - interval, err := s.intervalCalculator.Calculate(query.TimeRange, dsInterval, intervalv2.Min) - if err != nil { - return nil, err - } + interval := s.intervalCalculator.Calculate(query.TimeRange, dsInterval) var resolution int64 = 1 if model.Resolution >= 1 && model.Resolution <= 5 || model.Resolution == 10 { diff --git a/pkg/tsdb/loki/loki_test.go b/pkg/tsdb/loki/loki_test.go index 57c8041197d..da38e7fad03 100644 --- a/pkg/tsdb/loki/loki_test.go +++ b/pkg/tsdb/loki/loki_test.go @@ -178,8 +178,8 @@ type mockCalculator struct { interval intervalv2.Interval } -func (m mockCalculator) Calculate(timerange backend.TimeRange, minInterval time.Duration, intervalMode intervalv2.IntervalMode) (intervalv2.Interval, error) { - return m.interval, nil +func (m mockCalculator) Calculate(timerange backend.TimeRange, minInterval time.Duration) intervalv2.Interval { + return m.interval } func (m mockCalculator) CalculateSafeInterval(timerange backend.TimeRange, resolution int64) intervalv2.Interval { diff --git a/pkg/tsdb/prometheus/prometheus.go b/pkg/tsdb/prometheus/prometheus.go index 155e51e08b9..001ef65ce53 100644 --- a/pkg/tsdb/prometheus/prometheus.go +++ b/pkg/tsdb/prometheus/prometheus.go @@ -225,11 +225,7 @@ func formatLegend(metric model.Metric, query *PrometheusQuery) string { return string(result) } -func (s *Service) parseQuery(queries []backend.DataQuery, dsInfo *DatasourceInfo) ( - []*PrometheusQuery, error) { - var intervalMode string - var adjustedInterval time.Duration - +func (s *Service) parseQuery(queries []backend.DataQuery, dsInfo *DatasourceInfo) ([]*PrometheusQuery, error) { qs := []*PrometheusQuery{} for _, queryModel := range queries { jsonModel, err := simplejson.NewJson(queryModel.JSON) @@ -247,30 +243,18 @@ func (s *Service) parseQuery(queries []backend.DataQuery, dsInfo *DatasourceInfo end := queryModel.TimeRange.To queryInterval := jsonModel.Get("interval").MustString("") - foundInterval, err := intervalv2.GetIntervalFrom(dsInfo.TimeInterval, queryInterval, 0, 15*time.Second) - hasQueryInterval := queryInterval != "" - // Only use stepMode if we have interval in query, otherwise use "min" - if hasQueryInterval { - intervalMode = jsonModel.Get("stepMode").MustString("min") - } else { - intervalMode = "min" - } - - // Calculate interval value from query or data source settings or use default value + minInterval, err := intervalv2.GetIntervalFrom(dsInfo.TimeInterval, queryInterval, 0, 15*time.Second) if err != nil { return nil, err } - calculatedInterval, err := s.intervalCalculator.Calculate(queries[0].TimeRange, foundInterval, intervalv2.IntervalMode(intervalMode)) - if err != nil { - return nil, err - } + calculatedInterval := s.intervalCalculator.Calculate(queries[0].TimeRange, minInterval) + safeInterval := s.intervalCalculator.CalculateSafeInterval(queries[0].TimeRange, int64(safeRes)) + adjustedInterval := safeInterval.Value if calculatedInterval.Value > safeInterval.Value { adjustedInterval = calculatedInterval.Value - } else { - adjustedInterval = safeInterval.Value } intervalFactor := jsonModel.Get("intervalFactor").MustInt64(1) diff --git a/pkg/tsdb/prometheus/prometheus_test.go b/pkg/tsdb/prometheus/prometheus_test.go index 3b7cc37a40f..e4604af19bd 100644 --- a/pkg/tsdb/prometheus/prometheus_test.go +++ b/pkg/tsdb/prometheus/prometheus_test.go @@ -45,7 +45,7 @@ func TestPrometheus(t *testing.T) { require.Equal(t, `http_request_total{app="backend", device="mobile"}`, formatLegend(metric, query)) }) - t.Run("parsing query model with step and default stepMode", func(t *testing.T) { + t.Run("parsing query model with step", func(t *testing.T) { query := queryContext(`{ "expr": "go_goroutines", "format": "time_series", @@ -61,78 +61,6 @@ func TestPrometheus(t *testing.T) { require.Equal(t, time.Second*30, models[0].Step) }) - t.Run("parsing query model with step and exact stepMode", func(t *testing.T) { - query := queryContext(`{ - "expr": "go_goroutines", - "format": "time_series", - "refId": "A", - "stepMode": "exact", - "interval": "7s" - }`) - timeRange := backend.TimeRange{ - From: now, - To: now.Add(12 * time.Hour), - } - query.TimeRange = timeRange - models, err := service.parseQuery([]backend.DataQuery{query}, &DatasourceInfo{}) - require.NoError(t, err) - require.Equal(t, time.Second*7, models[0].Step) - }) - - t.Run("parsing query model with short step and max stepMode", func(t *testing.T) { - query := queryContext(`{ - "expr": "go_goroutines", - "format": "time_series", - "refId": "A", - "stepMode": "max", - "interval": "6s" - }`) - timeRange := backend.TimeRange{ - From: now, - To: now.Add(12 * time.Hour), - } - query.TimeRange = timeRange - models, err := service.parseQuery([]backend.DataQuery{query}, &DatasourceInfo{}) - require.NoError(t, err) - require.Equal(t, time.Second*6, models[0].Step) - }) - - t.Run("parsing query model with long step and max stepMode", func(t *testing.T) { - query := queryContext(`{ - "expr": "go_goroutines", - "format": "time_series", - "refId": "A", - "stepMode": "max", - "interval": "100s" - }`) - timeRange := backend.TimeRange{ - From: now, - To: now.Add(12 * time.Hour), - } - query.TimeRange = timeRange - models, err := service.parseQuery([]backend.DataQuery{query}, &DatasourceInfo{}) - require.NoError(t, err) - require.Equal(t, time.Second*30, models[0].Step) - }) - - t.Run("parsing query model with unsafe interval", func(t *testing.T) { - query := queryContext(`{ - "expr": "go_goroutines", - "format": "time_series", - "refId": "A", - "stepMode": "max", - "interval": "2s" - }`) - timeRange := backend.TimeRange{ - From: now, - To: now.Add(12 * time.Hour), - } - query.TimeRange = timeRange - models, err := service.parseQuery([]backend.DataQuery{query}, &DatasourceInfo{}) - require.NoError(t, err) - require.Equal(t, time.Second*5, models[0].Step) - }) - t.Run("parsing query model without step parameter", func(t *testing.T) { query := queryContext(`{ "expr": "go_goroutines", diff --git a/pkg/tsdb/sqleng/sql_engine.go b/pkg/tsdb/sqleng/sql_engine.go index 20894613592..c54bf3060f0 100644 --- a/pkg/tsdb/sqleng/sql_engine.go +++ b/pkg/tsdb/sqleng/sql_engine.go @@ -377,10 +377,7 @@ var Interpolate = func(query backend.DataQuery, timeRange backend.TimeRange, tim if err != nil { return "", err } - interval, err := sqlIntervalCalculator.Calculate(timeRange, minInterval, "min") - if err != nil { - return "", err - } + interval := sqlIntervalCalculator.Calculate(timeRange, minInterval) sql = strings.ReplaceAll(sql, "$__interval_ms", strconv.FormatInt(interval.Milliseconds(), 10)) sql = strings.ReplaceAll(sql, "$__interval", interval.Text) diff --git a/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx b/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx index d6068137c7c..575b0b910a5 100644 --- a/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx @@ -3,20 +3,16 @@ import React, { memo } from 'react'; import { css, cx } from '@emotion/css'; // Types -import { InlineFormLabel, RadioButtonGroup, Select } from '@grafana/ui'; -import { PromQuery, StepMode } from '../types'; +import { InlineFormLabel, RadioButtonGroup } from '@grafana/ui'; +import { PromQuery } from '../types'; import { PromExemplarField } from './PromExemplarField'; import { PrometheusDatasource } from '../datasource'; -import { STEP_MODES } from './PromQueryEditor'; -import { SelectableValue } from '@grafana/data'; export interface PromExploreExtraFieldProps { queryType: string; stepValue: string; - stepMode: StepMode; query: PromQuery; - onStepModeChange: (option: SelectableValue) => void; - onStepIntervalChange: (e: React.SyntheticEvent) => void; + onStepChange: (e: React.SyntheticEvent) => void; onKeyDownFunc: (e: React.KeyboardEvent) => void; onQueryTypeChange: (value: string) => void; onChange: (value: PromQuery) => void; @@ -24,18 +20,7 @@ export interface PromExploreExtraFieldProps { } export const PromExploreExtraField: React.FC = memo( - ({ - queryType, - stepValue, - stepMode, - query, - onChange, - onStepModeChange, - onStepIntervalChange, - onQueryTypeChange, - onKeyDownFunc, - datasource, - }) => { + ({ queryType, stepValue, query, onChange, onStepChange, onQueryTypeChange, onKeyDownFunc, datasource }) => { const rangeOptions = [ { value: 'range', label: 'Range', description: 'Run query over a range of time.' }, { @@ -82,20 +67,11 @@ export const PromExploreExtraField: React.FC = memo( > Step - diff --git a/public/app/plugins/datasource/prometheus/components/PromExploreQueryEditor.tsx b/public/app/plugins/datasource/prometheus/components/PromExploreQueryEditor.tsx index 2b2ed297435..3287560173c 100644 --- a/public/app/plugins/datasource/prometheus/components/PromExploreQueryEditor.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromExploreQueryEditor.tsx @@ -1,10 +1,10 @@ import React, { memo, FC, useEffect } from 'react'; // Types -import { ExploreQueryFieldProps, SelectableValue } from '@grafana/data'; +import { ExploreQueryFieldProps } from '@grafana/data'; import { PrometheusDatasource } from '../datasource'; -import { PromQuery, PromOptions, StepMode } from '../types'; +import { PromQuery, PromOptions } from '../types'; import PromQueryField from './PromQueryField'; import { PromExploreExtraField } from './PromExploreExtraField'; @@ -26,19 +26,7 @@ export const PromExploreQueryEditor: FC = (props: Props) => { onChange(nextQuery); } - function onChangeStepMode(mode: StepMode) { - const { query, onChange } = props; - const nextQuery = { ...query, stepMode: mode }; - onChange(nextQuery); - } - - function onStepModeChange(option: SelectableValue) { - if (option.value) { - onChangeStepMode(option.value); - } - } - - function onStepIntervalChange(e: React.SyntheticEvent) { + function onStepChange(e: React.SyntheticEvent) { if (e.currentTarget.value !== query.interval) { onChangeQueryStep(e.currentTarget.value); } @@ -78,10 +66,8 @@ export const PromExploreQueryEditor: FC = (props: Props) => { // Select "both" as default option when Explore is opened. In legacy requests, range and instant can be undefined. In this case, we want to run queries with "both". queryType={query.range === query.instant ? 'both' : query.instant ? 'instant' : 'range'} stepValue={query.interval || ''} - stepMode={query.stepMode || 'min'} onQueryTypeChange={onQueryTypeChange} - onStepModeChange={onStepModeChange} - onStepIntervalChange={onStepIntervalChange} + onStepChange={onStepChange} onKeyDownFunc={onReturnKeyDown} query={query} onChange={onChange} diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx index 9a7d4872708..38bc1ab25ef 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx @@ -4,7 +4,7 @@ import React, { PureComponent } from 'react'; // Types import { InlineFormLabel, LegacyForms, Select } from '@grafana/ui'; import { SelectableValue } from '@grafana/data'; -import { PromQuery, StepMode } from '../types'; +import { PromQuery } from '../types'; import PromQueryField from './PromQueryField'; import PromLink from './PromLink'; @@ -24,29 +24,11 @@ const INTERVAL_FACTOR_OPTIONS: Array> = map([1, 2, 3, 4, label: '1/' + value, })); -export const DEFAULT_STEP_MODE: SelectableValue = { - value: 'min', - label: 'Minimum', -}; - -export const STEP_MODES: Array> = [ - DEFAULT_STEP_MODE, - { - value: 'max', - label: 'Maximum', - }, - { - value: 'exact', - label: 'Exact', - }, -]; - interface State { legendFormat?: string; formatOption: SelectableValue; interval?: string; intervalFactorOption: SelectableValue; - stepMode: SelectableValue; instant: boolean; exemplar: boolean; } @@ -63,7 +45,6 @@ export class PromQueryEditor extends PureComponent legendFormat: '', interval: '', exemplar: true, - stepMode: DEFAULT_STEP_MODE.value, }; const query = Object.assign({}, defaultQuery, props.query); this.query = query; @@ -76,8 +57,6 @@ export class PromQueryEditor extends PureComponent formatOption: FORMAT_OPTIONS.find((option) => option.value === query.format) || FORMAT_OPTIONS[0], intervalFactorOption: INTERVAL_FACTOR_OPTIONS.find((option) => option.value === query.intervalFactor) || INTERVAL_FACTOR_OPTIONS[0], - // Step mode - stepMode: STEP_MODES.find((option) => option.value === query.stepMode) || DEFAULT_STEP_MODE, // Switch options instant: Boolean(query.instant), exemplar: Boolean(query.exemplar), @@ -110,11 +89,6 @@ export class PromQueryEditor extends PureComponent this.setState({ intervalFactorOption: option }, this.onRunQuery); }; - onStepChange = (option: SelectableValue) => { - this.query.stepMode = option.value; - this.setState({ stepMode: option }, this.onRunQuery); - }; - onLegendChange = (e: React.SyntheticEvent) => { const legendFormat = e.currentTarget.value; this.query.legendFormat = legendFormat; @@ -136,7 +110,7 @@ export class PromQueryEditor extends PureComponent render() { const { datasource, query, range, data } = this.props; - const { formatOption, instant, interval, intervalFactorOption, stepMode, legendFormat, exemplar } = this.state; + const { formatOption, instant, interval, intervalFactorOption, legendFormat, exemplar } = this.state; return (
- Use 'Minimum' or 'Maximum' step mode to set the lower or upper bounds - respectively on the interval between data points. For example, set "minimum 1h" to hint - that measurements were not taken more frequently. Use the 'Exact' step mode to set an - exact interval between data points. $__interval and $__rate_interval are - supported. + An additional lower limit for the step parameter of the Prometheus query and for the{' '} + $__interval and $__rate_interval variables. The limit is absolute and not + modified by the "Resolution" setting. } > - Step + Min step -
+
Resolution
} diff --git a/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap b/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap index 7130915b16a..6697e6ca81e 100644 --- a/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap +++ b/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap @@ -31,7 +31,8 @@ exports[`Render PromQueryEditor with basic options should render 1`] = ` - Use 'Minimum' or 'Maximum' step mode to set the lower or upper bounds respectively on the interval between data points. For example, set "minimum 1h" to hint that measurements were not taken more frequently. Use the 'Exact' step mode to set an exact interval between data points. + An additional lower limit for the step parameter of the Prometheus query and for the + $__interval @@ -39,47 +40,18 @@ exports[`Render PromQueryEditor with basic options should render 1`] = ` $__rate_interval - are supported. + variables. The limit is absolute and not modified by the "Resolution" setting. } - width={5} + width={7} > - Step + Min step - @@ -192,7 +164,6 @@ exports[`Render PromQueryEditor with basic options should render 1`] = ` "interval": "", "legendFormat": "", "refId": "A", - "stepMode": "min", } } /> diff --git a/public/app/plugins/datasource/prometheus/datasource.test.ts b/public/app/plugins/datasource/prometheus/datasource.test.ts index 6e35e767380..9e71fe63408 100644 --- a/public/app/plugins/datasource/prometheus/datasource.test.ts +++ b/public/app/plugins/datasource/prometheus/datasource.test.ts @@ -18,7 +18,7 @@ import { prometheusRegularEscape, prometheusSpecialRegexEscape, } from './datasource'; -import { PromOptions, PromQuery, StepMode } from './types'; +import { PromOptions, PromQuery } from './types'; import { VariableHide } from '../../../features/variables/types'; import { describe } from '../../../../test/lib/common'; import { QueryOptions } from 'app/types'; @@ -1685,60 +1685,6 @@ describe('PrometheusDatasource', () => { templateSrvStub.replace = jest.fn((a: string) => a); }); }); - - describe('adjustInterval', () => { - const dynamicInterval = 15; - const stepInterval = 35; - const range = 1642; - describe('when max step option is used', () => { - it('should return the minimum interval', () => { - let intervalFactor = 1; - let interval = ds.adjustInterval(dynamicInterval, stepInterval, range, intervalFactor, 'max'); - expect(interval).toBe(dynamicInterval * intervalFactor); - - intervalFactor = 3; - interval = ds.adjustInterval(dynamicInterval, stepInterval, range, intervalFactor, 'max'); - expect(interval).toBe(stepInterval); - }); - }); - describe('when min step option is used', () => { - it('should return the maximum interval', () => { - let intervalFactor = 1; - let interval = ds.adjustInterval(dynamicInterval, stepInterval, range, intervalFactor, 'min'); - expect(interval).toBe(stepInterval); - - intervalFactor = 3; - interval = ds.adjustInterval(dynamicInterval, stepInterval, range, intervalFactor, 'min'); - expect(interval).toBe(dynamicInterval * intervalFactor); - }); - }); - describe('when exact step option is used', () => { - it('should return the stepInterval * intervalFactor', () => { - let intervalFactor = 3; - let interval = ds.adjustInterval(dynamicInterval, stepInterval, range, intervalFactor, 'exact'); - expect(interval).toBe(stepInterval * intervalFactor); - }); - }); - it('should not return a value less than the safe interval', () => { - let newStepInterval = 0.13; - let intervalFactor = 1; - let stepMode: StepMode = 'min'; - let safeInterval = range / 11000; - if (safeInterval > 1) { - safeInterval = Math.ceil(safeInterval); - } - let interval = ds.adjustInterval(dynamicInterval, newStepInterval, range, intervalFactor, stepMode); - expect(interval).toBeGreaterThanOrEqual(safeInterval); - - stepMode = 'max'; - interval = ds.adjustInterval(dynamicInterval, newStepInterval, range, intervalFactor, stepMode); - expect(interval).toBeGreaterThanOrEqual(safeInterval); - - stepMode = 'exact'; - interval = ds.adjustInterval(dynamicInterval, newStepInterval, range, intervalFactor, stepMode); - expect(interval).toBeGreaterThanOrEqual(safeInterval); - }); - }); }); describe('PrometheusDatasource for POST', () => { diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index 71f433ee2d0..a58fb999373 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -39,11 +39,9 @@ import { PromQueryRequest, PromScalarData, PromVectorData, - StepMode, } from './types'; import { PrometheusVariableSupport } from './variables'; import PrometheusMetricFindQuery from './metric_find_query'; -import { DEFAULT_STEP_MODE } from './components/PromQueryEditor'; export const ANNOTATION_QUERY_STEP_DEFAULT = '60s'; const EXEMPLARS_NOT_AVAILABLE = 'Exemplars for this query are not available.'; @@ -417,12 +415,11 @@ export class PrometheusDatasource extends DataSourceApi end: 0, }; const range = Math.ceil(end - start); - // target.stepMode specifies whether to use min, max or exact step - const stepMode = target.stepMode || (DEFAULT_STEP_MODE.value as StepMode); + // options.interval is the dynamically calculated interval let interval: number = rangeUtil.intervalToSeconds(options.interval); // Minimum interval ("Min step"), if specified for the query, or same as interval otherwise. - const stepInterval = rangeUtil.intervalToSeconds( + const minInterval = rangeUtil.intervalToSeconds( this.templateSrv.replace(target.interval || options.interval, options.scopedVars) ); // Scrape interval as specified for the query ("Min step") or otherwise taken from the datasource. @@ -433,7 +430,7 @@ export class PrometheusDatasource extends DataSourceApi const intervalFactor = target.intervalFactor || 1; // Adjust the interval to take into account any specified minimum and interval factor plus Prometheus limits - const adjustedInterval = this.adjustInterval(interval, stepInterval, range, intervalFactor, stepMode); + const adjustedInterval = this.adjustInterval(interval, minInterval, range, intervalFactor); let scopedVars = { ...options.scopedVars, ...this.getRangeScopedVars(options.range), @@ -486,13 +483,7 @@ export class PrometheusDatasource extends DataSourceApi return { __rate_interval: { text: rateInterval + 's', value: rateInterval + 's' } }; } - adjustInterval( - dynamicInterval: number, - stepInterval: number, - range: number, - intervalFactor: number, - stepMode: StepMode - ) { + adjustInterval(interval: number, minInterval: number, range: number, intervalFactor: number) { // Prometheus will drop queries that might return more than 11000 data points. // Calculate a safe interval as an additional minimum to take into account. // Fractional safeIntervals are allowed, however serve little purpose if the interval is greater than 1 @@ -501,20 +492,7 @@ export class PrometheusDatasource extends DataSourceApi if (safeInterval > 1) { safeInterval = Math.ceil(safeInterval); } - - //Calculate adjusted interval based on the current step option - let adjustedInterval = safeInterval; - if (stepMode === 'min') { - adjustedInterval = Math.max(dynamicInterval * intervalFactor, stepInterval, safeInterval); - } else if (stepMode === 'max') { - adjustedInterval = Math.min(dynamicInterval * intervalFactor, stepInterval); - if (adjustedInterval < safeInterval) { - adjustedInterval = safeInterval; - } - } else if (stepMode === 'exact') { - adjustedInterval = Math.max(stepInterval * intervalFactor, safeInterval); - } - return adjustedInterval; + return Math.max(interval * intervalFactor, minInterval, safeInterval); } performTimeSeriesQuery(query: PromQueryRequest, start: number, end: number) { diff --git a/public/app/plugins/datasource/prometheus/types.ts b/public/app/plugins/datasource/prometheus/types.ts index 1cfab31b85c..cdf857d0b8d 100644 --- a/public/app/plugins/datasource/prometheus/types.ts +++ b/public/app/plugins/datasource/prometheus/types.ts @@ -10,7 +10,6 @@ export interface PromQuery extends DataQuery { hinting?: boolean; interval?: string; intervalFactor?: number; - stepMode?: StepMode; legendFormat?: string; valueWithRefId?: boolean; requestId?: string; @@ -18,8 +17,6 @@ export interface PromQuery extends DataQuery { showingTable?: boolean; } -export type StepMode = 'min' | 'max' | 'exact'; - export interface PromOptions extends DataSourceJsonData { timeInterval: string; queryTimeout: string;