mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: alerting: adjust step-calculation to be the same as in frontend (#42033)
* loki: alerting: adjust step-calculation to be the same as in frontend * loki: simplified test * lint fix
This commit is contained in:
parent
d11ae6dc3f
commit
037fd9cc8c
@ -197,7 +197,7 @@ func parseQuery(dsInfo *datasourceInfo, queryContext *backend.QueryDataRequest)
|
||||
resolution = model.Resolution
|
||||
}
|
||||
|
||||
step := time.Duration(int64(query.Interval) * resolution)
|
||||
step := calculateStep(query.Interval, query.TimeRange.To.Sub(query.TimeRange.From), resolution)
|
||||
|
||||
qs = append(qs, &lokiQuery{
|
||||
Expr: model.Expr,
|
||||
|
@ -1,7 +1,6 @@
|
||||
package loki
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -41,7 +40,7 @@ func TestLoki(t *testing.T) {
|
||||
require.Equal(t, `http_request_total{app="backend", device="mobile"}`, formatLegend(metric, query))
|
||||
})
|
||||
|
||||
t.Run("parsing query model with step", func(t *testing.T) {
|
||||
t.Run("parsing query model", func(t *testing.T) {
|
||||
queryContext := &backend.QueryDataRequest{
|
||||
Queries: []backend.DataQuery{
|
||||
{
|
||||
@ -65,55 +64,6 @@ func TestLoki(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, time.Second*30, models[0].Step)
|
||||
})
|
||||
|
||||
t.Run("parsing query model without step parameter", func(t *testing.T) {
|
||||
queryContext1 := &backend.QueryDataRequest{
|
||||
Queries: []backend.DataQuery{
|
||||
{
|
||||
JSON: []byte(`
|
||||
{
|
||||
"expr": "go_goroutines",
|
||||
"format": "time_series",
|
||||
"refId": "A"
|
||||
}`,
|
||||
),
|
||||
TimeRange: backend.TimeRange{
|
||||
From: time.Now().Add(-48 * time.Hour),
|
||||
To: time.Now(),
|
||||
},
|
||||
Interval: time.Minute * 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
dsInfo := &datasourceInfo{}
|
||||
models, err := parseQuery(dsInfo, queryContext1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, time.Minute*2, models[0].Step)
|
||||
|
||||
queryContext2 := &backend.QueryDataRequest{
|
||||
Queries: []backend.DataQuery{
|
||||
{
|
||||
JSON: []byte(`
|
||||
{
|
||||
"expr": "go_goroutines",
|
||||
"format": "time_series",
|
||||
"refId": "A"
|
||||
}`,
|
||||
),
|
||||
TimeRange: backend.TimeRange{
|
||||
From: time.Now().Add(-48 * time.Hour),
|
||||
To: time.Now(),
|
||||
},
|
||||
Interval: time.Second * 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
models, err = parseQuery(dsInfo, queryContext2)
|
||||
require.NoError(t, err)
|
||||
fmt.Println(models)
|
||||
require.Equal(t, time.Second*2, models[0].Step)
|
||||
})
|
||||
}
|
||||
|
||||
func TestParseResponse(t *testing.T) {
|
||||
|
31
pkg/tsdb/loki/step.go
Normal file
31
pkg/tsdb/loki/step.go
Normal file
@ -0,0 +1,31 @@
|
||||
package loki
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
// round the duration to the nearest millisecond larger-or-equal-to the duration
|
||||
func ceilMs(duration time.Duration) time.Duration {
|
||||
floatMs := float64(duration.Nanoseconds()) / 1000.0 / 1000.0
|
||||
ceilMs := math.Ceil(floatMs)
|
||||
return time.Duration(ceilMs) * time.Millisecond
|
||||
}
|
||||
|
||||
func durationMax(d1 time.Duration, d2 time.Duration) time.Duration {
|
||||
if d1.Nanoseconds() >= d2.Nanoseconds() {
|
||||
return d1
|
||||
} else {
|
||||
return d2
|
||||
}
|
||||
}
|
||||
|
||||
func calculateStep(baseInterval time.Duration, timeRange time.Duration, resolution int64) time.Duration {
|
||||
step := time.Duration(baseInterval.Nanoseconds() * resolution)
|
||||
|
||||
safeStep := timeRange / 11000
|
||||
|
||||
chosenStep := durationMax(step, safeStep)
|
||||
|
||||
return ceilMs(chosenStep)
|
||||
}
|
57
pkg/tsdb/loki/step_test.go
Normal file
57
pkg/tsdb/loki/step_test.go
Normal file
@ -0,0 +1,57 @@
|
||||
package loki
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLokiStep(t *testing.T) {
|
||||
t.Run("base case", func(t *testing.T) {
|
||||
require.Equal(t, time.Second*14, calculateStep(time.Second*7, time.Second, 2))
|
||||
})
|
||||
|
||||
t.Run("step should be at least 1 millisecond", func(t *testing.T) {
|
||||
require.Equal(t, time.Millisecond*1, calculateStep(time.Microsecond*500, time.Second, 1))
|
||||
})
|
||||
|
||||
t.Run("safeInterval should happen", func(t *testing.T) {
|
||||
// safeInterval
|
||||
require.Equal(t, time.Second*3, calculateStep(time.Second*2, time.Second*33000, 1))
|
||||
})
|
||||
|
||||
t.Run("step should math.Ceil in milliseconds", func(t *testing.T) {
|
||||
require.Equal(t, time.Millisecond*2, calculateStep(time.Microsecond*1234, time.Second*1, 1))
|
||||
})
|
||||
|
||||
t.Run("step should math.Ceil in milliseconds, even if safeInterval happens", func(t *testing.T) {
|
||||
require.Equal(t, time.Millisecond*3001, calculateStep(time.Second*2, time.Second*33001, 1))
|
||||
})
|
||||
|
||||
t.Run("resolution should happen", func(t *testing.T) {
|
||||
require.Equal(t, time.Second*5, calculateStep(time.Second*1, time.Second*100, 5))
|
||||
})
|
||||
|
||||
t.Run("safeInterval check should happen after resolution is used", func(t *testing.T) {
|
||||
require.Equal(t, time.Second*4, calculateStep(time.Second*2, time.Second*33000, 2))
|
||||
})
|
||||
|
||||
t.Run("survive interval=0", func(t *testing.T) {
|
||||
// interval=0. this should never happen, but we make sure we return something sane
|
||||
// (in this case safeInterval will take care of the problem)
|
||||
require.Equal(t, time.Second*2, calculateStep(time.Second*0, time.Second*22000, 1))
|
||||
})
|
||||
|
||||
t.Run("survive resolution=0", func(t *testing.T) {
|
||||
// resolution=0. this should never happen, but we make sure we return something sane
|
||||
// (in this case safeInterval will take care of the problem)
|
||||
require.Equal(t, time.Second*2, calculateStep(time.Second*1, time.Second*22000, 0))
|
||||
})
|
||||
|
||||
t.Run("survive interval=0 and resolution=0", func(t *testing.T) {
|
||||
// resolution=0 and interval=0. this should never happen, but we make sure we return something sane
|
||||
// (in this case safeInterval will take care of the problem)
|
||||
require.Equal(t, time.Second*2, calculateStep(time.Second*0, time.Second*22000, 0))
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user