mirror of
				https://github.com/grafana/grafana.git
				synced 2025-02-25 18:55:37 -06:00 
			
		
		
		
	feat(alerting): add support for "no_value" evaluator
This commit is contained in:
		@@ -9,37 +9,86 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	defaultTypes []string = []string{"gt", "lt"}
 | 
			
		||||
	rangedTypes  []string = []string{"within_range", "outside_range"}
 | 
			
		||||
	defaultTypes   []string = []string{"gt", "lt"}
 | 
			
		||||
	rangedTypes    []string = []string{"within_range", "outside_range"}
 | 
			
		||||
	paramlessTypes []string = []string{"no_value"}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AlertEvaluator interface {
 | 
			
		||||
	Eval(timeSeries *tsdb.TimeSeries, reducedValue float64) bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DefaultAlertEvaluator struct {
 | 
			
		||||
type ParameterlessEvaluator struct {
 | 
			
		||||
	Type string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *ParameterlessEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool {
 | 
			
		||||
	return len(series.Points) == 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ThresholdEvaluator struct {
 | 
			
		||||
	Type      string
 | 
			
		||||
	Threshold float64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *DefaultAlertEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool {
 | 
			
		||||
func newThresholdEvaludator(typ string, model *simplejson.Json) (*ThresholdEvaluator, error) {
 | 
			
		||||
	params := model.Get("params").MustArray()
 | 
			
		||||
	if len(params) == 0 {
 | 
			
		||||
		return nil, alerting.ValidationError{Reason: "Evaluator missing threshold parameter"}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	firstParam, ok := params[0].(json.Number)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, alerting.ValidationError{Reason: "Evaluator has invalid parameter"}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defaultEval := &ThresholdEvaluator{Type: typ}
 | 
			
		||||
	defaultEval.Threshold, _ = firstParam.Float64()
 | 
			
		||||
	return defaultEval, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *ThresholdEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool {
 | 
			
		||||
	switch e.Type {
 | 
			
		||||
	case "gt":
 | 
			
		||||
		return reducedValue > e.Threshold
 | 
			
		||||
	case "lt":
 | 
			
		||||
		return reducedValue < e.Threshold
 | 
			
		||||
	case "no_value":
 | 
			
		||||
		return len(series.Points) == 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RangedAlertEvaluator struct {
 | 
			
		||||
type RangedEvaluator struct {
 | 
			
		||||
	Type  string
 | 
			
		||||
	Lower float64
 | 
			
		||||
	Upper float64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *RangedAlertEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool {
 | 
			
		||||
func newRangedEvaluator(typ string, model *simplejson.Json) (*RangedEvaluator, error) {
 | 
			
		||||
	params := model.Get("params").MustArray()
 | 
			
		||||
	if len(params) == 0 {
 | 
			
		||||
		return nil, alerting.ValidationError{Reason: "Evaluator missing threshold parameter"}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	firstParam, ok := params[0].(json.Number)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, alerting.ValidationError{Reason: "Evaluator has invalid parameter"}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	secondParam, ok := params[1].(json.Number)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, alerting.ValidationError{Reason: "Evaluator has invalid second parameter"}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rangedEval := &RangedEvaluator{Type: typ}
 | 
			
		||||
	rangedEval.Lower, _ = firstParam.Float64()
 | 
			
		||||
	rangedEval.Upper, _ = secondParam.Float64()
 | 
			
		||||
	return rangedEval, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *RangedEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool {
 | 
			
		||||
	switch e.Type {
 | 
			
		||||
	case "within_range":
 | 
			
		||||
		return (e.Lower < reducedValue && e.Upper > reducedValue) || (e.Upper < reducedValue && e.Lower > reducedValue)
 | 
			
		||||
@@ -56,32 +105,16 @@ func NewAlertEvaluator(model *simplejson.Json) (AlertEvaluator, error) {
 | 
			
		||||
		return nil, alerting.ValidationError{Reason: "Evaluator missing type property"}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	params := model.Get("params").MustArray()
 | 
			
		||||
	if len(params) == 0 {
 | 
			
		||||
		return nil, alerting.ValidationError{Reason: "Evaluator missing threshold parameter"}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	firstParam, ok := params[0].(json.Number)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, alerting.ValidationError{Reason: "Evaluator has invalid parameter"}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if inSlice(typ, defaultTypes) {
 | 
			
		||||
		defaultEval := &DefaultAlertEvaluator{Type: typ}
 | 
			
		||||
		defaultEval.Threshold, _ = firstParam.Float64()
 | 
			
		||||
		return defaultEval, nil
 | 
			
		||||
		return newThresholdEvaludator(typ, model)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if inSlice(typ, rangedTypes) {
 | 
			
		||||
		secondParam, ok := params[1].(json.Number)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, alerting.ValidationError{Reason: "Evaluator has invalid second parameter"}
 | 
			
		||||
		}
 | 
			
		||||
		return newRangedEvaluator(typ, model)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		rangedEval := &RangedAlertEvaluator{Type: typ}
 | 
			
		||||
		rangedEval.Lower, _ = firstParam.Float64()
 | 
			
		||||
		rangedEval.Upper, _ = secondParam.Float64()
 | 
			
		||||
		return rangedEval, nil
 | 
			
		||||
	if inSlice(typ, paramlessTypes) {
 | 
			
		||||
		return &ParameterlessEvaluator{Type: typ}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, alerting.ValidationError{Reason: "Evaludator invalid evaluator type"}
 | 
			
		||||
 
 | 
			
		||||
@@ -42,4 +42,8 @@ func TestEvalutors(t *testing.T) {
 | 
			
		||||
		So(test(`{"type": "outside_range", "params": [100, 1] }`, 1000), ShouldBeTrue)
 | 
			
		||||
		So(test(`{"type": "outside_range", "params": [100, 1] }`, 50), ShouldBeFalse)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	Convey("no_value", t, func() {
 | 
			
		||||
		So(test(`{"type": "no_value", "params": [] }`, 1000), ShouldBeTrue)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ func TestQueryCondition(t *testing.T) {
 | 
			
		||||
				})
 | 
			
		||||
 | 
			
		||||
				Convey("Can read evaluator", func() {
 | 
			
		||||
					evaluator, ok := ctx.condition.Evaluator.(*DefaultAlertEvaluator)
 | 
			
		||||
					evaluator, ok := ctx.condition.Evaluator.(*ThresholdEvaluator)
 | 
			
		||||
					So(ok, ShouldBeTrue)
 | 
			
		||||
					So(evaluator.Type, ShouldEqual, "gt")
 | 
			
		||||
				})
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user