Alerting: Add LogicOr operation option (#89258)
--------- Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com>
This commit is contained in:
co-authored by
brendamuir
parent
62abaea8f5
commit
126169f3ca
@@ -53,6 +53,19 @@ The pending period specifies how long the condition must be met before firing, e
|
||||
|
||||
You can also set the pending period to zero to skip it and have the alert fire immediately once the condition is met.
|
||||
|
||||
## Condition operator
|
||||
|
||||
There are several condition operators available.
|
||||
|
||||
- **and**: Two conditions before and after must be true for the overall condition to be true.
|
||||
- **or**: If one of conditions before and after are true, the overall condition is true.
|
||||
- **logic-or**: If the condition before logic-or is true, the overall condition is immediately true, without evaluating subsequent conditions.
|
||||
|
||||
Here are some examples of operators.
|
||||
|
||||
- `TRUE and TRUE or FALSE and FALSE` evaluate to `FALSE`, because last two conditions return `FALSE`.
|
||||
- `TRUE and TRUE logic-or FALSE and FALSE` evaluate to `TRUE`, because the preceding condition returns `TRUE`.
|
||||
|
||||
## Evaluation example
|
||||
|
||||
Keep in mind:
|
||||
|
||||
@@ -136,7 +136,7 @@ These functions are available for **Reduce** and **Classic condition** expressio
|
||||
|
||||
An alert condition is the query or expression that determines whether the alert fires or not depending on the value it yields. There can be only one condition which determines the triggering of the alert.
|
||||
|
||||
After you have defined your queries and/or expressions, choose one of them as the alert rule condition. By default, the last expression added is used as the alert condition.
|
||||
After you have defined your queries and expressions, choose one of them as the alert rule condition. By default, the last expression added is used as the alert condition.
|
||||
|
||||
When the queried data satisfies the defined condition, Grafana triggers the associated alert, which can be configured to send notifications through various channels like email, Slack, or PagerDuty.
|
||||
|
||||
|
||||
@@ -79,6 +79,11 @@ func (cmd *ConditionsCmd) Execute(ctx context.Context, t time.Time, vars mathexp
|
||||
// matches contains the list of matches for all conditions
|
||||
matches := make([]EvalMatch, 0)
|
||||
for i, cond := range cmd.Conditions {
|
||||
// Avoid operate subsequent conditions for LogicOr when it is already firing, see #87483
|
||||
if isFiring && cond.Operator == ConditionOperatorLogicOr {
|
||||
break
|
||||
}
|
||||
|
||||
isCondFiring, isCondNoData, condMatches, err := cmd.executeCond(ctx, t, cond, vars)
|
||||
if err != nil {
|
||||
return mathexp.Results{}, err
|
||||
@@ -221,7 +226,7 @@ func (cmd *ConditionsCmd) Type() string {
|
||||
}
|
||||
|
||||
func compareWithOperator(b1, b2 bool, operator ConditionOperatorType) bool {
|
||||
if operator == "or" {
|
||||
if operator == ConditionOperatorOr || operator == ConditionOperatorLogicOr {
|
||||
return b1 || b2
|
||||
} else {
|
||||
return b1 && b2
|
||||
@@ -271,8 +276,9 @@ type ConditionEvalJSON struct {
|
||||
type ConditionOperatorType string
|
||||
|
||||
const (
|
||||
ConditionOperatorAnd ConditionOperatorType = "and"
|
||||
ConditionOperatorOr ConditionOperatorType = "or"
|
||||
ConditionOperatorAnd ConditionOperatorType = "and"
|
||||
ConditionOperatorOr ConditionOperatorType = "or"
|
||||
ConditionOperatorLogicOr ConditionOperatorType = "logic-or"
|
||||
)
|
||||
|
||||
type ConditionOperatorJSON struct {
|
||||
@@ -297,8 +303,11 @@ func NewConditionCmd(refID string, ccj []ConditionJSON) (*ConditionsCmd, error)
|
||||
for i, cj := range ccj {
|
||||
cond := condition{}
|
||||
|
||||
if i > 0 && cj.Operator.Type != "and" && cj.Operator.Type != "or" {
|
||||
return nil, fmt.Errorf("condition %v operator must be `and` or `or`", i+1)
|
||||
if i > 0 &&
|
||||
cj.Operator.Type != ConditionOperatorAnd &&
|
||||
cj.Operator.Type != ConditionOperatorOr &&
|
||||
cj.Operator.Type != ConditionOperatorLogicOr {
|
||||
return nil, fmt.Errorf("condition %v operator must be `and`, `or` or `logic-or`", i+1)
|
||||
}
|
||||
cond.Operator = cj.Operator.Type
|
||||
|
||||
|
||||
@@ -595,6 +595,46 @@ func TestConditionsCmd(t *testing.T) {
|
||||
v.SetMeta([]EvalMatch{{Value: util.Pointer(5.0)}, {Metric: "NoData"}})
|
||||
return newResults(v)
|
||||
},
|
||||
}, {
|
||||
name: "LogicOr will stop subsequent logic checks in condition: true AND true LogicOr false AND false",
|
||||
vars: mathexp.Vars{
|
||||
"A": mathexp.Results{
|
||||
Values: []mathexp.Value{
|
||||
newSeries(util.Pointer(1.0), util.Pointer(5.0)),
|
||||
},
|
||||
},
|
||||
},
|
||||
cmd: &ConditionsCmd{
|
||||
Conditions: []condition{
|
||||
{
|
||||
InputRefID: "A",
|
||||
Reducer: reducer("max"),
|
||||
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 2},
|
||||
},
|
||||
{
|
||||
InputRefID: "A",
|
||||
Reducer: reducer("min"),
|
||||
Operator: "and",
|
||||
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 0},
|
||||
},
|
||||
{
|
||||
InputRefID: "A",
|
||||
Reducer: reducer("avg"),
|
||||
Operator: "logic-or",
|
||||
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 6},
|
||||
},
|
||||
{
|
||||
InputRefID: "A",
|
||||
Reducer: reducer("last"),
|
||||
Operator: "and",
|
||||
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 6},
|
||||
},
|
||||
}},
|
||||
expected: func() mathexp.Results {
|
||||
v := newNumber(util.Pointer(1.0))
|
||||
v.SetMeta([]EvalMatch{{Value: util.Pointer(5.0)}, {Value: util.Pointer(1.0)}})
|
||||
return newResults(v)
|
||||
},
|
||||
}}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -525,7 +525,8 @@
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"and",
|
||||
"or"
|
||||
"or",
|
||||
"logic-or"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
}
|
||||
|
||||
@@ -559,7 +559,8 @@
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"and",
|
||||
"or"
|
||||
"or",
|
||||
"logic-or"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": "classic_conditions",
|
||||
"resourceVersion": "1709915973363",
|
||||
"resourceVersion": "1723675389127",
|
||||
"creationTimestamp": "2024-02-21T22:09:26Z"
|
||||
},
|
||||
"spec": {
|
||||
@@ -273,7 +273,8 @@
|
||||
"type": {
|
||||
"enum": [
|
||||
"and",
|
||||
"or"
|
||||
"or",
|
||||
"logic-or"
|
||||
],
|
||||
"type": "string",
|
||||
"x-enum-description": {}
|
||||
|
||||
@@ -48,6 +48,7 @@ const evalFunctions = [
|
||||
const evalOperators = [
|
||||
{ text: 'OR', value: 'or' },
|
||||
{ text: 'AND', value: 'and' },
|
||||
{ text: 'LOGIC OR', value: 'logic-or' },
|
||||
];
|
||||
|
||||
const reducerTypes = [
|
||||
|
||||
@@ -65,7 +65,7 @@ export const Condition = ({ condition, index, onChange, onRemoveCondition, refId
|
||||
};
|
||||
|
||||
const buttonWidth = css`
|
||||
width: 60px;
|
||||
width: 75px;
|
||||
`;
|
||||
|
||||
const isRange =
|
||||
|
||||
Reference in New Issue
Block a user