Prometheus: Revert stepMode functionality (#38982)

* Revert "Prometheus: add functionality to specify desired step interval in dashboards panels (#36422)"

This reverts commit ddf5b65c51.
Co-authored-by: Ivana Huckova <ivana.huckova@gmail.com>

* Revert "Explore: add functionality for supporting different step modes in prometheus (#37829)"

This reverts commit f433cfd8d9.
Co-authored-by: Ivana Huckova <ivana.huckova@gmail.com>

* Revert stepMode BE implementation from #36796
Co-authored-by: "Ivana Huckova" <ivana.huckova@gmail.com>
This commit is contained in:
Giordano Ricci
2021-09-09 14:05:08 +02:00
committed by GitHub
co-authored by Ivana Huckova
parent 419ead99aa
commit dc36f15fbb
20 changed files with 76 additions and 415 deletions
+1 -4
View File
@@ -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
}
@@ -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))
+2 -5
View File
@@ -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)
+5 -17
View File
@@ -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 {
+8 -18
View File
@@ -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)
})
}
+6 -25
View File
@@ -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 {
@@ -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)
})
}
+1 -4
View File
@@ -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 {
+2 -2
View File
@@ -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 {
+5 -21
View File
@@ -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)
+1 -73
View File
@@ -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",
+1 -4
View File
@@ -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)