feat(alerting): adds within_range and outside_range evaluators
closes #5829
This commit is contained in:
@@ -28,11 +28,30 @@ func (e *DefaultAlertEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultAlertEvaluator(model *simplejson.Json) (*DefaultAlertEvaluator, error) {
|
type RangedAlertEvaluator struct {
|
||||||
evaluator := &DefaultAlertEvaluator{}
|
Type string
|
||||||
|
Lower float64
|
||||||
|
Upper float64
|
||||||
|
}
|
||||||
|
|
||||||
evaluator.Type = model.Get("type").MustString()
|
func (e *RangedAlertEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool {
|
||||||
if evaluator.Type == "" {
|
switch e.Type {
|
||||||
|
case "within_range":
|
||||||
|
return (e.Lower < reducedValue && e.Upper > reducedValue) || (e.Upper < reducedValue && e.Lower > reducedValue)
|
||||||
|
case "outside_range":
|
||||||
|
return (e.Upper < reducedValue && e.Lower < reducedValue) || (e.Upper > reducedValue && e.Lower > reducedValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAlertEvaluator(model *simplejson.Json) (AlertEvaluator, error) {
|
||||||
|
defaultTypes := []string{"gt", "lt"}
|
||||||
|
rangedTypes := []string{"within_range", "outside_range"}
|
||||||
|
|
||||||
|
typ := model.Get("type").MustString()
|
||||||
|
|
||||||
|
if typ == "" {
|
||||||
return nil, alerting.ValidationError{Reason: "Evaluator missing type property"}
|
return nil, alerting.ValidationError{Reason: "Evaluator missing type property"}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,11 +60,35 @@ func NewDefaultAlertEvaluator(model *simplejson.Json) (*DefaultAlertEvaluator, e
|
|||||||
return nil, alerting.ValidationError{Reason: "Evaluator missing threshold parameter"}
|
return nil, alerting.ValidationError{Reason: "Evaluator missing threshold parameter"}
|
||||||
}
|
}
|
||||||
|
|
||||||
threshold, ok := params[0].(json.Number)
|
firstParam, ok := params[0].(json.Number)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, alerting.ValidationError{Reason: "Evaluator has invalid threshold parameter"}
|
return nil, alerting.ValidationError{Reason: "Evaluator has invalid threshold parameter"}
|
||||||
}
|
}
|
||||||
|
|
||||||
evaluator.Threshold, _ = threshold.Float64()
|
if stringInSlice(typ, defaultTypes) {
|
||||||
return evaluator, nil
|
evaluator := &DefaultAlertEvaluator{Type: typ}
|
||||||
|
evaluator.Threshold, _ = firstParam.Float64()
|
||||||
|
return evaluator, nil
|
||||||
|
} else if stringInSlice(typ, rangedTypes) {
|
||||||
|
secondParam, ok := params[1].(json.Number)
|
||||||
|
if !ok {
|
||||||
|
return nil, alerting.ValidationError{Reason: "Evaluator has invalid threshold parameter"}
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluator := &RangedAlertEvaluator{Type: typ}
|
||||||
|
evaluator.Lower, _ = firstParam.Float64()
|
||||||
|
evaluator.Upper, _ = secondParam.Float64()
|
||||||
|
return evaluator, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, alerting.ValidationError{Reason: "Evaludator invalid evaluator type"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringInSlice(a string, list []string) bool {
|
||||||
|
for _, b := range list {
|
||||||
|
if b == a {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package conditions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
)
|
||||||
|
|
||||||
|
func test(json string, reducedValue float64) bool {
|
||||||
|
jsonModel, err := simplejson.NewJson([]byte(json))
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
evaluator, err := NewAlertEvaluator(jsonModel)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
return evaluator.Eval(&tsdb.TimeSeries{}, reducedValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEvalutors(t *testing.T) {
|
||||||
|
Convey("greater then", t, func() {
|
||||||
|
So(test(`{"type": "gt", "params": [1] }`, 3), ShouldBeTrue)
|
||||||
|
So(test(`{"type": "gt", "params": [3] }`, 1), ShouldBeFalse)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("less then", t, func() {
|
||||||
|
So(test(`{"type": "lt", "params": [1] }`, 3), ShouldBeFalse)
|
||||||
|
So(test(`{"type": "lt", "params": [3] }`, 1), ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("within_range", t, func() {
|
||||||
|
So(test(`{"type": "within_range", "params": [1, 100] }`, 3), ShouldBeTrue)
|
||||||
|
So(test(`{"type": "within_range", "params": [1, 100] }`, 300), ShouldBeFalse)
|
||||||
|
So(test(`{"type": "within_range", "params": [100, 1] }`, 3), ShouldBeTrue)
|
||||||
|
So(test(`{"type": "within_range", "params": [100, 1] }`, 300), ShouldBeFalse)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("outside_range", t, func() {
|
||||||
|
So(test(`{"type": "outside_range", "params": [1, 100] }`, 1000), ShouldBeTrue)
|
||||||
|
So(test(`{"type": "outside_range", "params": [1, 100] }`, 50), ShouldBeFalse)
|
||||||
|
So(test(`{"type": "outside_range", "params": [100, 1] }`, 1000), ShouldBeTrue)
|
||||||
|
So(test(`{"type": "outside_range", "params": [100, 1] }`, 50), ShouldBeFalse)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -133,7 +133,7 @@ func NewQueryCondition(model *simplejson.Json, index int) (*QueryCondition, erro
|
|||||||
condition.Reducer = NewSimpleReducer(reducerJson.Get("type").MustString())
|
condition.Reducer = NewSimpleReducer(reducerJson.Get("type").MustString())
|
||||||
|
|
||||||
evaluatorJson := model.Get("evaluator")
|
evaluatorJson := model.Get("evaluator")
|
||||||
evaluator, err := NewDefaultAlertEvaluator(evaluatorJson)
|
evaluator, err := NewAlertEvaluator(evaluatorJson)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user