mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Prometheus: Implement stepMode for alerting queries (#36796)
* Add select component for choosing step option * Add onStepChange * Add functionality for max step * Rename minInterval to stepInterval to describe min, max and exact step interval * Change select option from standard to exact * Add new type StepType for better type safety * Add tests for adjustInterval * Add functionality and tests for exact step option * Prometheus: Spell out min and max in select component * Prometheus: Change width of step select component and add placeholder * Prometheus: Adjust for the factor in exact step * Prometheus: Update tooltip of step lable to include max and exact options and add padding to select component to give it some breathing room from other components * Update snapshot for step tooltip * Prometheus: make tooltip more informative * Prometheus: add tooltip to interval input element * Prometheus: extract default step option * Prometheus: update snapshot for PromQueryEditor * Prometheus: change step labels to uppercase * Prometheus: define a default step option * Prometheus: use default step option in both ui component and logic * Prometheus: update snapshot for PromQueryEditor * Prometheus: refactor datasource.ts for better readability * Prometheus: change tool tip for step * Prometheus: update snapshots * Prometheus: add correct styling * Prometheus: update snapshots * Prometheus change variable name to something less superfluous * Prometheus: refactor * Prometheus: add new test for adjustInterval * Docs: Update docummentation on the step parameter for prometheus * Prometheus: make step input field smaller and change placeholder text to 15s * Prometheus: update snapshots * Prometheus: Make stepMode uniform in all places in the code * Adjust step based on stepMode * Adjust comment * Check if we have queryInterval * Refactor, add safe interval * Fix merge resolutions * Fix tests and add tests * Update snapshot * Update docs/sources/datasources/prometheus.md Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * Update docs/sources/datasources/prometheus.md Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * Update docs/sources/datasources/prometheus.md Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * Update docs/sources/datasources/prometheus.md Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * Update docs/sources/datasources/prometheus.md Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * Update docs/sources/datasources/prometheus.md Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * Update docs/sources/datasources/prometheus.md Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * Implement calculation with intervalMode in calculator.go * Update tests, add calculate safe interval method * Replace panic with error * Update pkg/tsdb/interval/interval_test.go Co-authored-by: idafurjes <36131195+idafurjes@users.noreply.github.com> * Update pkg/tsdb/calculator_test.go Co-authored-by: idafurjes <36131195+idafurjes@users.noreply.github.com> * Impotrt require * Remove lint errors Co-authored-by: Olof Bourghardt <ob655088@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: idafurjes <36131195+idafurjes@users.noreply.github.com>
This commit is contained in:
@@ -23,6 +23,7 @@ import (
|
||||
var (
|
||||
plog log.Logger
|
||||
legendFormat *regexp.Regexp = regexp.MustCompile(`\{\{\s*(.+?)\s*\}\}`)
|
||||
safeRes int64 = 11000
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -122,6 +123,9 @@ func formatLegend(metric model.Metric, query *PrometheusQuery) string {
|
||||
|
||||
func (e *PrometheusExecutor) parseQuery(dsInfo *models.DataSource, query plugins.DataQuery) (
|
||||
[]*PrometheusQuery, error) {
|
||||
var intervalMode string
|
||||
var adjustedInterval time.Duration
|
||||
|
||||
qs := []*PrometheusQuery{}
|
||||
for _, queryModel := range query.Queries {
|
||||
expr, err := queryModel.Model.Get("expr").String()
|
||||
@@ -141,14 +145,34 @@ func (e *PrometheusExecutor) parseQuery(dsInfo *models.DataSource, query plugins
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dsInterval, err := interval.GetIntervalFrom(dsInfo, queryModel.Model, time.Second*15)
|
||||
hasQueryInterval := queryModel.Model.Get("interval").MustString("") != ""
|
||||
// Only use stepMode if we have interval in query, otherwise use "min"
|
||||
if hasQueryInterval {
|
||||
intervalMode = queryModel.Model.Get("stepMode").MustString("min")
|
||||
} else {
|
||||
intervalMode = "min"
|
||||
}
|
||||
|
||||
// Calculate interval value from query or data source settings or use default value
|
||||
intervalValue, err := interval.GetIntervalFrom(dsInfo, queryModel.Model, time.Second*15)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
calculatedInterval, err := e.intervalCalculator.Calculate(*query.TimeRange, intervalValue, intervalMode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
safeInterval := e.intervalCalculator.CalculateSafeInterval(*query.TimeRange, safeRes)
|
||||
|
||||
if calculatedInterval.Value > safeInterval.Value {
|
||||
adjustedInterval = calculatedInterval.Value
|
||||
} else {
|
||||
adjustedInterval = safeInterval.Value
|
||||
}
|
||||
|
||||
intervalFactor := queryModel.Model.Get("intervalFactor").MustInt64(1)
|
||||
interval := e.intervalCalculator.Calculate(*query.TimeRange, dsInterval)
|
||||
step := time.Duration(int64(interval.Value) * intervalFactor)
|
||||
step := time.Duration(int64(adjustedInterval) * intervalFactor)
|
||||
|
||||
qs = append(qs, &PrometheusQuery{
|
||||
Expr: expr,
|
||||
|
||||
@@ -63,7 +63,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", func(t *testing.T) {
|
||||
t.Run("parsing query model with step and default stepMode", func(t *testing.T) {
|
||||
query := queryContext(`{
|
||||
"expr": "go_goroutines",
|
||||
"format": "time_series",
|
||||
@@ -76,6 +76,66 @@ 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 := plugins.NewDataTimeRange("12h", "now")
|
||||
query.TimeRange = &timerange
|
||||
models, err := executor.parseQuery(dsInfo, query)
|
||||
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 := plugins.NewDataTimeRange("12h", "now")
|
||||
query.TimeRange = &timerange
|
||||
models, err := executor.parseQuery(dsInfo, query)
|
||||
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 := plugins.NewDataTimeRange("12h", "now")
|
||||
query.TimeRange = &timerange
|
||||
models, err := executor.parseQuery(dsInfo, query)
|
||||
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 := plugins.NewDataTimeRange("12h", "now")
|
||||
query.TimeRange = &timerange
|
||||
models, err := executor.parseQuery(dsInfo, query)
|
||||
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",
|
||||
|
||||
Reference in New Issue
Block a user