Alerting: Add multiple threshold operators (#99516)
The following operators are being added: - Equal - Not Equal - Greater or Equal - Less or Equal - Within Range Inclusive - Outside Range Inclusive
This commit is contained in:
@@ -48,9 +48,9 @@ func (rangedEvaluator) Kind() EvaluatorKind {
|
||||
// an AlertEvaluator depending on evaluation operator.
|
||||
func newAlertEvaluator(model ConditionEvalJSON) (evaluator, error) {
|
||||
switch model.Type {
|
||||
case "gt", "lt":
|
||||
case "gt", "lt", "eq", "ne", "gte", "lte":
|
||||
return newThresholdEvaluator(model)
|
||||
case "within_range", "outside_range":
|
||||
case "within_range", "outside_range", "within_range_included", "outside_range_included":
|
||||
return newRangedEvaluator(model)
|
||||
case "no_value":
|
||||
return &noValueEvaluator{}, nil
|
||||
@@ -70,6 +70,14 @@ func (e *thresholdEvaluator) Eval(reducedValue mathexp.Number) bool {
|
||||
return *fv > e.Threshold
|
||||
case "lt":
|
||||
return *fv < e.Threshold
|
||||
case "eq":
|
||||
return *fv == e.Threshold
|
||||
case "ne":
|
||||
return *fv != e.Threshold
|
||||
case "gte":
|
||||
return *fv >= e.Threshold
|
||||
case "lte":
|
||||
return *fv <= e.Threshold
|
||||
}
|
||||
|
||||
return false
|
||||
@@ -113,6 +121,10 @@ func (e *rangedEvaluator) Eval(reducedValue mathexp.Number) bool {
|
||||
return (e.Lower < *fv && e.Upper > *fv) || (e.Upper < *fv && e.Lower > *fv)
|
||||
case "outside_range":
|
||||
return (e.Upper < *fv && e.Lower < *fv) || (e.Upper > *fv && e.Lower > *fv)
|
||||
case "within_range_included":
|
||||
return (e.Lower <= *fv && e.Upper >= *fv) || (e.Upper <= *fv && e.Lower >= *fv)
|
||||
case "outside_range_included":
|
||||
return (e.Upper <= *fv && e.Lower <= *fv) || (e.Upper >= *fv && e.Lower >= *fv)
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
@@ -40,6 +40,48 @@ func TestThresholdEvaluator(t *testing.T) {
|
||||
inputNumber: newNumber(util.Pointer(1.0)),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "value 1 is eq 1: false",
|
||||
evaluator: &thresholdEvaluator{"eq", 1},
|
||||
inputNumber: newNumber(util.Pointer(1.0)),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "value 0 is eq 0: false",
|
||||
evaluator: &thresholdEvaluator{"eq", 0},
|
||||
inputNumber: newNumber(util.Pointer(0.0)),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "value 1 is eq 0: false",
|
||||
evaluator: &thresholdEvaluator{"eq", 0},
|
||||
inputNumber: newNumber(util.Pointer(1.0)),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "value 0 is eq 1: false",
|
||||
evaluator: &thresholdEvaluator{"eq", 1},
|
||||
inputNumber: newNumber(util.Pointer(0.0)),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "value 1 is ne 1: false",
|
||||
evaluator: &thresholdEvaluator{"ne", 1},
|
||||
inputNumber: newNumber(util.Pointer(1.0)),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "value 3 is gte 3: false",
|
||||
evaluator: &thresholdEvaluator{"gte", 3},
|
||||
inputNumber: newNumber(util.Pointer(3.0)),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "value 5 is lte 4: false",
|
||||
evaluator: &thresholdEvaluator{"lte", 4},
|
||||
inputNumber: newNumber(util.Pointer(5.0)),
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -712,8 +712,14 @@
|
||||
"enum": [
|
||||
"gt",
|
||||
"lt",
|
||||
"eq",
|
||||
"ne",
|
||||
"gte",
|
||||
"lte",
|
||||
"within_range",
|
||||
"outside_range"
|
||||
"outside_range",
|
||||
"within_range_included",
|
||||
"outside_range_included"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
}
|
||||
@@ -744,8 +750,14 @@
|
||||
"enum": [
|
||||
"gt",
|
||||
"lt",
|
||||
"eq",
|
||||
"ne",
|
||||
"gte",
|
||||
"lte",
|
||||
"within_range",
|
||||
"outside_range"
|
||||
"outside_range",
|
||||
"within_range_included",
|
||||
"outside_range_included"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
}
|
||||
@@ -1013,4 +1025,4 @@
|
||||
},
|
||||
"additionalProperties": true,
|
||||
"$schema": "https://json-schema.org/draft-04/schema#"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -754,8 +754,14 @@
|
||||
"enum": [
|
||||
"gt",
|
||||
"lt",
|
||||
"eq",
|
||||
"ne",
|
||||
"gte",
|
||||
"lte",
|
||||
"within_range",
|
||||
"outside_range"
|
||||
"outside_range",
|
||||
"within_range_included",
|
||||
"outside_range_included"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
}
|
||||
@@ -786,8 +792,14 @@
|
||||
"enum": [
|
||||
"gt",
|
||||
"lt",
|
||||
"eq",
|
||||
"ne",
|
||||
"gte",
|
||||
"lte",
|
||||
"within_range",
|
||||
"outside_range"
|
||||
"outside_range",
|
||||
"within_range_included",
|
||||
"outside_range_included"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
}
|
||||
@@ -1071,4 +1083,4 @@
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"$schema": "https://json-schema.org/draft-04/schema#"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,8 +395,14 @@
|
||||
"enum": [
|
||||
"gt",
|
||||
"lt",
|
||||
"eq",
|
||||
"ne",
|
||||
"gte",
|
||||
"lte",
|
||||
"within_range",
|
||||
"outside_range"
|
||||
"outside_range",
|
||||
"within_range_included",
|
||||
"outside_range_included"
|
||||
],
|
||||
"type": "string",
|
||||
"x-enum-description": {}
|
||||
@@ -427,8 +433,14 @@
|
||||
"enum": [
|
||||
"gt",
|
||||
"lt",
|
||||
"eq",
|
||||
"ne",
|
||||
"gte",
|
||||
"lte",
|
||||
"within_range",
|
||||
"outside_range"
|
||||
"outside_range",
|
||||
"within_range_included",
|
||||
"outside_range_included"
|
||||
],
|
||||
"type": "string",
|
||||
"x-enum-description": {}
|
||||
@@ -579,4 +591,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+96
-4
@@ -32,18 +32,30 @@ type ThresholdCommand struct {
|
||||
type ThresholdType string
|
||||
|
||||
const (
|
||||
ThresholdIsAbove ThresholdType = "gt"
|
||||
ThresholdIsBelow ThresholdType = "lt"
|
||||
ThresholdIsWithinRange ThresholdType = "within_range"
|
||||
ThresholdIsOutsideRange ThresholdType = "outside_range"
|
||||
ThresholdIsAbove ThresholdType = "gt"
|
||||
ThresholdIsBelow ThresholdType = "lt"
|
||||
ThresholdIsEqual ThresholdType = "eq"
|
||||
ThresholdIsNotEqual ThresholdType = "ne"
|
||||
ThresholdIsGreaterThanEqual ThresholdType = "gte"
|
||||
ThresholdIsLessThanEqual ThresholdType = "lte"
|
||||
ThresholdIsWithinRange ThresholdType = "within_range"
|
||||
ThresholdIsOutsideRange ThresholdType = "outside_range"
|
||||
ThresholdIsWithinRangeIncluded ThresholdType = "within_range_included"
|
||||
ThresholdIsOutsideRangeIncluded ThresholdType = "outside_range_included"
|
||||
)
|
||||
|
||||
var (
|
||||
supportedThresholdFuncs = []string{
|
||||
string(ThresholdIsAbove),
|
||||
string(ThresholdIsBelow),
|
||||
string(ThresholdIsEqual),
|
||||
string(ThresholdIsNotEqual),
|
||||
string(ThresholdIsGreaterThanEqual),
|
||||
string(ThresholdIsLessThanEqual),
|
||||
string(ThresholdIsWithinRange),
|
||||
string(ThresholdIsOutsideRange),
|
||||
string(ThresholdIsWithinRangeIncluded),
|
||||
string(ThresholdIsOutsideRangeIncluded),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -60,6 +72,16 @@ func NewThresholdCommand(refID, referenceVar string, thresholdFunc ThresholdType
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 2", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = withinRangePredicate{left: conditions[0], right: conditions[1]}
|
||||
case ThresholdIsWithinRangeIncluded:
|
||||
if len(conditions) < 2 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 2", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = withinRangeIncludedPredicate{left: conditions[0], right: conditions[1]}
|
||||
case ThresholdIsOutsideRangeIncluded:
|
||||
if len(conditions) < 2 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 2", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = outsideRangeIncludedPredicate{left: conditions[0], right: conditions[1]}
|
||||
case ThresholdIsAbove:
|
||||
if len(conditions) < 1 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions))
|
||||
@@ -70,6 +92,26 @@ func NewThresholdCommand(refID, referenceVar string, thresholdFunc ThresholdType
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = lessThanPredicate{value: conditions[0]}
|
||||
case ThresholdIsEqual:
|
||||
if len(conditions) < 1 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = equalPredicate{value: conditions[0]}
|
||||
case ThresholdIsNotEqual:
|
||||
if len(conditions) < 1 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = notEqualPredicate{value: conditions[0]}
|
||||
case ThresholdIsGreaterThanEqual:
|
||||
if len(conditions) < 1 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = greaterThanEqualPredicate{value: conditions[0]}
|
||||
case ThresholdIsLessThanEqual:
|
||||
if len(conditions) < 1 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = lessThanEqualPredicate{value: conditions[0]}
|
||||
default:
|
||||
return nil, fmt.Errorf("expected threshold function to be one of [%s], got %s", strings.Join(supportedThresholdFuncs, ", "), thresholdFunc)
|
||||
}
|
||||
@@ -279,6 +321,24 @@ func (r outsideRangePredicate) Eval(f float64) bool {
|
||||
return f < r.left || f > r.right
|
||||
}
|
||||
|
||||
type withinRangeIncludedPredicate struct {
|
||||
left float64
|
||||
right float64
|
||||
}
|
||||
|
||||
func (r withinRangeIncludedPredicate) Eval(f float64) bool {
|
||||
return f >= r.left && f <= r.right
|
||||
}
|
||||
|
||||
type outsideRangeIncludedPredicate struct {
|
||||
left float64
|
||||
right float64
|
||||
}
|
||||
|
||||
func (r outsideRangeIncludedPredicate) Eval(f float64) bool {
|
||||
return f <= r.left || f >= r.right
|
||||
}
|
||||
|
||||
type lessThanPredicate struct {
|
||||
value float64
|
||||
}
|
||||
@@ -294,3 +354,35 @@ type greaterThanPredicate struct {
|
||||
func (r greaterThanPredicate) Eval(f float64) bool {
|
||||
return f > r.value
|
||||
}
|
||||
|
||||
type equalPredicate struct {
|
||||
value float64
|
||||
}
|
||||
|
||||
func (r equalPredicate) Eval(f float64) bool {
|
||||
return f == r.value
|
||||
}
|
||||
|
||||
type notEqualPredicate struct {
|
||||
value float64
|
||||
}
|
||||
|
||||
func (r notEqualPredicate) Eval(f float64) bool {
|
||||
return f != r.value
|
||||
}
|
||||
|
||||
type greaterThanEqualPredicate struct {
|
||||
value float64
|
||||
}
|
||||
|
||||
func (r greaterThanEqualPredicate) Eval(f float64) bool {
|
||||
return f >= r.value
|
||||
}
|
||||
|
||||
type lessThanEqualPredicate struct {
|
||||
value float64
|
||||
}
|
||||
|
||||
func (r lessThanEqualPredicate) Eval(f float64) bool {
|
||||
return f <= r.value
|
||||
}
|
||||
|
||||
@@ -38,6 +38,26 @@ func TestNewThresholdCommand(t *testing.T) {
|
||||
args: []float64{0},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "eq",
|
||||
args: []float64{0},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "ne",
|
||||
args: []float64{0},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "gte",
|
||||
args: []float64{0},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "lte",
|
||||
args: []float64{0},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "within_range",
|
||||
args: []float64{0, 1},
|
||||
@@ -48,6 +68,16 @@ func TestNewThresholdCommand(t *testing.T) {
|
||||
args: []float64{0, 1},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "within_range_included",
|
||||
args: []float64{0, 1},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "outside_range_included",
|
||||
args: []float64{0, 1},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "gt",
|
||||
args: []float64{},
|
||||
@@ -60,6 +90,30 @@ func TestNewThresholdCommand(t *testing.T) {
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "eq",
|
||||
args: []float64{},
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "ne",
|
||||
args: []float64{},
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "gte",
|
||||
args: []float64{},
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "lte",
|
||||
args: []float64{},
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "within_range",
|
||||
args: []float64{0},
|
||||
@@ -72,6 +126,18 @@ func TestNewThresholdCommand(t *testing.T) {
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "within_range_included",
|
||||
args: []float64{0},
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "outside_range_included",
|
||||
args: []float64{0},
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -249,6 +315,22 @@ func TestIsSupportedThresholdFunc(t *testing.T) {
|
||||
function: ThresholdIsBelow,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsEqual,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsNotEqual,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsGreaterThanEqual,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsLessThanEqual,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsWithinRange,
|
||||
supported: true,
|
||||
@@ -257,6 +339,14 @@ func TestIsSupportedThresholdFunc(t *testing.T) {
|
||||
function: ThresholdIsOutsideRange,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsWithinRangeIncluded,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsOutsideRangeIncluded,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: "foo",
|
||||
supported: false,
|
||||
|
||||
Reference in New Issue
Block a user