mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 18:30:41 -06:00
Loki: alerting: handle variables like __interval and __range (#42126)
This commit is contained in:
parent
ccd162f806
commit
24d4c8a9d1
@ -182,38 +182,6 @@ func formatLegend(metric model.Metric, query *lokiQuery) string {
|
||||
return string(result)
|
||||
}
|
||||
|
||||
func parseQuery(dsInfo *datasourceInfo, queryContext *backend.QueryDataRequest) ([]*lokiQuery, error) {
|
||||
qs := []*lokiQuery{}
|
||||
for _, query := range queryContext.Queries {
|
||||
model := &ResponseModel{}
|
||||
err := json.Unmarshal(query.JSON, model)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
start := query.TimeRange.From
|
||||
end := query.TimeRange.To
|
||||
|
||||
var resolution int64 = 1
|
||||
if model.Resolution >= 1 && model.Resolution <= 5 || model.Resolution == 10 {
|
||||
resolution = model.Resolution
|
||||
}
|
||||
|
||||
step := calculateStep(query.Interval, query.TimeRange.To.Sub(query.TimeRange.From), resolution)
|
||||
|
||||
qs = append(qs, &lokiQuery{
|
||||
Expr: model.Expr,
|
||||
Step: step,
|
||||
LegendFormat: model.LegendFormat,
|
||||
Start: start,
|
||||
End: end,
|
||||
RefID: query.RefID,
|
||||
})
|
||||
}
|
||||
|
||||
return qs, nil
|
||||
}
|
||||
|
||||
func parseResponse(value *loghttp.QueryResponse, query *lokiQuery) (data.Frames, error) {
|
||||
frames := data.Frames{}
|
||||
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/loki/pkg/loghttp"
|
||||
p "github.com/prometheus/common/model"
|
||||
@ -39,31 +38,6 @@ func TestLoki(t *testing.T) {
|
||||
|
||||
require.Equal(t, `http_request_total{app="backend", device="mobile"}`, formatLegend(metric, query))
|
||||
})
|
||||
|
||||
t.Run("parsing query model", func(t *testing.T) {
|
||||
queryContext := &backend.QueryDataRequest{
|
||||
Queries: []backend.DataQuery{
|
||||
{
|
||||
JSON: []byte(`
|
||||
{
|
||||
"expr": "go_goroutines",
|
||||
"format": "time_series",
|
||||
"refId": "A"
|
||||
}`,
|
||||
),
|
||||
TimeRange: backend.TimeRange{
|
||||
From: time.Now().Add(-30 * time.Second),
|
||||
To: time.Now(),
|
||||
},
|
||||
Interval: time.Second * 30,
|
||||
},
|
||||
},
|
||||
}
|
||||
dsInfo := &datasourceInfo{}
|
||||
models, err := parseQuery(dsInfo, queryContext)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, time.Second*30, models[0].Step)
|
||||
})
|
||||
}
|
||||
|
||||
func TestParseResponse(t *testing.T) {
|
||||
|
75
pkg/tsdb/loki/parse_query.go
Normal file
75
pkg/tsdb/loki/parse_query.go
Normal file
@ -0,0 +1,75 @@
|
||||
package loki
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
||||
)
|
||||
|
||||
const (
|
||||
varInterval = "$__interval"
|
||||
varIntervalMs = "$__interval_ms"
|
||||
varRange = "$__range"
|
||||
varRangeS = "$__range_s"
|
||||
varRangeMs = "$__range_ms"
|
||||
)
|
||||
|
||||
func interpolateVariables(expr string, interval time.Duration, timeRange time.Duration) string {
|
||||
intervalText := intervalv2.FormatDuration(interval)
|
||||
intervalMsText := strconv.FormatInt(int64(interval/time.Millisecond), 10)
|
||||
|
||||
rangeMs := timeRange.Milliseconds()
|
||||
rangeSRounded := int64(math.Round(float64(rangeMs) / 1000.0))
|
||||
rangeMsText := strconv.FormatInt(rangeMs, 10)
|
||||
rangeSText := strconv.FormatInt(rangeSRounded, 10)
|
||||
|
||||
expr = strings.ReplaceAll(expr, varIntervalMs, intervalMsText)
|
||||
expr = strings.ReplaceAll(expr, varInterval, intervalText)
|
||||
expr = strings.ReplaceAll(expr, varRangeMs, rangeMsText)
|
||||
expr = strings.ReplaceAll(expr, varRangeS, rangeSText)
|
||||
expr = strings.ReplaceAll(expr, varRange, rangeSText+"s")
|
||||
|
||||
return expr
|
||||
}
|
||||
|
||||
func parseQuery(dsInfo *datasourceInfo, queryContext *backend.QueryDataRequest) ([]*lokiQuery, error) {
|
||||
qs := []*lokiQuery{}
|
||||
for _, query := range queryContext.Queries {
|
||||
model := &ResponseModel{}
|
||||
err := json.Unmarshal(query.JSON, model)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
start := query.TimeRange.From
|
||||
end := query.TimeRange.To
|
||||
|
||||
var resolution int64 = 1
|
||||
if model.Resolution >= 1 && model.Resolution <= 5 || model.Resolution == 10 {
|
||||
resolution = model.Resolution
|
||||
}
|
||||
|
||||
interval := query.Interval
|
||||
timeRange := query.TimeRange.To.Sub(query.TimeRange.From)
|
||||
|
||||
step := calculateStep(interval, timeRange, resolution)
|
||||
|
||||
expr := interpolateVariables(model.Expr, interval, timeRange)
|
||||
|
||||
qs = append(qs, &lokiQuery{
|
||||
Expr: expr,
|
||||
Step: step,
|
||||
LegendFormat: model.LegendFormat,
|
||||
Start: start,
|
||||
End: end,
|
||||
RefID: query.RefID,
|
||||
})
|
||||
}
|
||||
|
||||
return qs, nil
|
||||
}
|
54
pkg/tsdb/loki/parse_query_test.go
Normal file
54
pkg/tsdb/loki/parse_query_test.go
Normal file
@ -0,0 +1,54 @@
|
||||
package loki
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseQuery(t *testing.T) {
|
||||
t.Run("parsing query model", func(t *testing.T) {
|
||||
queryContext := &backend.QueryDataRequest{
|
||||
Queries: []backend.DataQuery{
|
||||
{
|
||||
JSON: []byte(`
|
||||
{
|
||||
"expr": "go_goroutines $__interval $__interval_ms $__range $__range_s $__range_ms",
|
||||
"format": "time_series",
|
||||
"refId": "A"
|
||||
}`,
|
||||
),
|
||||
TimeRange: backend.TimeRange{
|
||||
From: time.Now().Add(-3000 * time.Second),
|
||||
To: time.Now(),
|
||||
},
|
||||
Interval: time.Second * 15,
|
||||
MaxDataPoints: 200,
|
||||
},
|
||||
},
|
||||
}
|
||||
dsInfo := &datasourceInfo{}
|
||||
models, err := parseQuery(dsInfo, queryContext)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, time.Second*15, models[0].Step)
|
||||
require.Equal(t, "go_goroutines 15s 15000 3000s 3000 3000000", models[0].Expr)
|
||||
})
|
||||
t.Run("interpolate variables, range between 1s and 0.5s", func(t *testing.T) {
|
||||
expr := "go_goroutines $__interval $__interval_ms $__range $__range_s $__range_ms"
|
||||
|
||||
interval := time.Millisecond * 50
|
||||
timeRange := time.Millisecond * 750
|
||||
|
||||
require.Equal(t, "go_goroutines 50ms 50 1s 1 750", interpolateVariables(expr, interval, timeRange))
|
||||
})
|
||||
t.Run("parsing query model, range below 0.5s", func(t *testing.T) {
|
||||
expr := "go_goroutines $__interval $__interval_ms $__range $__range_s $__range_ms"
|
||||
|
||||
interval := time.Millisecond * 50
|
||||
timeRange := time.Millisecond * 250
|
||||
|
||||
require.Equal(t, "go_goroutines 50ms 50 0s 0 250", interpolateVariables(expr, interval, timeRange))
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user