Commit 62e8a039 by Torkel Ödegaard

refactor(alerting): refactoring PR for OR conditions, #6579

parent 457ae743
...@@ -120,7 +120,7 @@ func AlertTest(c *middleware.Context, dto dtos.AlertTestCommand) Response { ...@@ -120,7 +120,7 @@ func AlertTest(c *middleware.Context, dto dtos.AlertTestCommand) Response {
dtoRes := &dtos.AlertTestResult{ dtoRes := &dtos.AlertTestResult{
Firing: res.Firing, Firing: res.Firing,
FiringEval: res.FiringEval, ConditionEvals: res.ConditionEvals,
} }
if res.Error != nil { if res.Error != nil {
......
...@@ -36,7 +36,7 @@ type AlertTestCommand struct { ...@@ -36,7 +36,7 @@ type AlertTestCommand struct {
type AlertTestResult struct { type AlertTestResult struct {
Firing bool `json:"firing"` Firing bool `json:"firing"`
FiringEval string `json:"firingEvaluation"` ConditionEvals string `json:"conditionEvals"`
TimeMs string `json:"timeMs"` TimeMs string `json:"timeMs"`
Error string `json:"error,omitempty"` Error string `json:"error,omitempty"`
EvalMatches []*EvalMatch `json:"matches,omitempty"` EvalMatches []*EvalMatch `json:"matches,omitempty"`
......
...@@ -173,7 +173,7 @@ func NewQueryCondition(model *simplejson.Json, index int) (*QueryCondition, erro ...@@ -173,7 +173,7 @@ func NewQueryCondition(model *simplejson.Json, index int) (*QueryCondition, erro
condition.Evaluator = evaluator condition.Evaluator = evaluator
operatorJson := model.Get("operator") operatorJson := model.Get("operator")
operator := operatorJson.Get("type").MustString() operator := operatorJson.Get("type").MustString("and")
condition.Operator = operator condition.Operator = operator
return &condition, nil return &condition, nil
......
...@@ -17,8 +17,7 @@ type EvalContext struct { ...@@ -17,8 +17,7 @@ type EvalContext struct {
EvalMatches []*EvalMatch EvalMatches []*EvalMatch
Logs []*ResultLogEntry Logs []*ResultLogEntry
Error error Error error
Description string ConditionEvals string
FiringEval string
StartTime time.Time StartTime time.Time
EndTime time.Time EndTime time.Time
Rule *Rule Rule *Rule
......
...@@ -2,6 +2,7 @@ package alerting ...@@ -2,6 +2,7 @@ package alerting
import ( import (
"strconv" "strconv"
"strings"
"time" "time"
"github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/log"
...@@ -22,7 +23,8 @@ func NewEvalHandler() *DefaultEvalHandler { ...@@ -22,7 +23,8 @@ func NewEvalHandler() *DefaultEvalHandler {
func (e *DefaultEvalHandler) Eval(context *EvalContext) { func (e *DefaultEvalHandler) Eval(context *EvalContext) {
firing := true firing := true
firingEval := "" conditionEvals := ""
for i := 0; i < len(context.Rule.Conditions); i++ { for i := 0; i < len(context.Rule.Conditions); i++ {
condition := context.Rule.Conditions[i] condition := context.Rule.Conditions[i]
cr, err := condition.Eval(context) cr, err := condition.Eval(context)
...@@ -36,24 +38,22 @@ func (e *DefaultEvalHandler) Eval(context *EvalContext) { ...@@ -36,24 +38,22 @@ func (e *DefaultEvalHandler) Eval(context *EvalContext) {
} }
// calculating Firing based on operator // calculating Firing based on operator
operator := "AND"
if cr.Operator == "or" { if cr.Operator == "or" {
firing = firing || cr.Firing firing = firing || cr.Firing
operator = "OR"
} else { } else {
firing = firing && cr.Firing firing = firing && cr.Firing
} }
if i > 0 { if i > 0 {
firingEval = "[" + firingEval + " " + operator + " " + strconv.FormatBool(cr.Firing) + "]" conditionEvals = "[" + conditionEvals + " " + strings.ToUpper(cr.Operator) + " " + strconv.FormatBool(cr.Firing) + "]"
} else { } else {
firingEval = strconv.FormatBool(firing) conditionEvals = strconv.FormatBool(firing)
} }
context.EvalMatches = append(context.EvalMatches, cr.EvalMatches...) context.EvalMatches = append(context.EvalMatches, cr.EvalMatches...)
} }
context.FiringEval = firingEval + " = " + strconv.FormatBool(firing) context.ConditionEvals = conditionEvals + " = " + strconv.FormatBool(firing)
context.Firing = firing context.Firing = firing
context.EndTime = time.Now() context.EndTime = time.Now()
elapsedTime := context.EndTime.Sub(context.StartTime) / time.Millisecond elapsedTime := context.EndTime.Sub(context.StartTime) / time.Millisecond
......
...@@ -30,7 +30,7 @@ func TestAlertingExecutor(t *testing.T) { ...@@ -30,7 +30,7 @@ func TestAlertingExecutor(t *testing.T) {
handler.Eval(context) handler.Eval(context)
So(context.Firing, ShouldEqual, true) So(context.Firing, ShouldEqual, true)
So(context.FiringEval, ShouldEqual, "true = true") So(context.ConditionEvals, ShouldEqual, "true = true")
}) })
Convey("Show return false with not passing asdf", func() { Convey("Show return false with not passing asdf", func() {
...@@ -43,7 +43,7 @@ func TestAlertingExecutor(t *testing.T) { ...@@ -43,7 +43,7 @@ func TestAlertingExecutor(t *testing.T) {
handler.Eval(context) handler.Eval(context)
So(context.Firing, ShouldEqual, false) So(context.Firing, ShouldEqual, false)
So(context.FiringEval, ShouldEqual, "[true AND false] = false") So(context.ConditionEvals, ShouldEqual, "[true AND false] = false")
}) })
Convey("Show return true if any of the condition is passing with OR operator", func() { Convey("Show return true if any of the condition is passing with OR operator", func() {
...@@ -56,7 +56,7 @@ func TestAlertingExecutor(t *testing.T) { ...@@ -56,7 +56,7 @@ func TestAlertingExecutor(t *testing.T) {
handler.Eval(context) handler.Eval(context)
So(context.Firing, ShouldEqual, true) So(context.Firing, ShouldEqual, true)
So(context.FiringEval, ShouldEqual, "[true OR false] = true") So(context.ConditionEvals, ShouldEqual, "[true OR false] = true")
}) })
Convey("Show return false if any of the condition is failing with AND operator", func() { Convey("Show return false if any of the condition is failing with AND operator", func() {
...@@ -69,7 +69,7 @@ func TestAlertingExecutor(t *testing.T) { ...@@ -69,7 +69,7 @@ func TestAlertingExecutor(t *testing.T) {
handler.Eval(context) handler.Eval(context)
So(context.Firing, ShouldEqual, false) So(context.Firing, ShouldEqual, false)
So(context.FiringEval, ShouldEqual, "[true AND false] = false") So(context.ConditionEvals, ShouldEqual, "[true AND false] = false")
}) })
Convey("Show return true if one condition is failing with nested OR operator", func() { Convey("Show return true if one condition is failing with nested OR operator", func() {
...@@ -83,7 +83,7 @@ func TestAlertingExecutor(t *testing.T) { ...@@ -83,7 +83,7 @@ func TestAlertingExecutor(t *testing.T) {
handler.Eval(context) handler.Eval(context)
So(context.Firing, ShouldEqual, true) So(context.Firing, ShouldEqual, true)
So(context.FiringEval, ShouldEqual, "[[true AND true] OR false] = true") So(context.ConditionEvals, ShouldEqual, "[[true AND true] OR false] = true")
}) })
Convey("Show return false if one condition is passing with nested OR operator", func() { Convey("Show return false if one condition is passing with nested OR operator", func() {
...@@ -97,7 +97,7 @@ func TestAlertingExecutor(t *testing.T) { ...@@ -97,7 +97,7 @@ func TestAlertingExecutor(t *testing.T) {
handler.Eval(context) handler.Eval(context)
So(context.Firing, ShouldEqual, false) So(context.Firing, ShouldEqual, false)
So(context.FiringEval, ShouldEqual, "[[true AND false] OR false] = false") So(context.ConditionEvals, ShouldEqual, "[[true AND false] OR false] = false")
}) })
Convey("Show return false if a condition is failing with nested AND operator", func() { Convey("Show return false if a condition is failing with nested AND operator", func() {
...@@ -111,7 +111,7 @@ func TestAlertingExecutor(t *testing.T) { ...@@ -111,7 +111,7 @@ func TestAlertingExecutor(t *testing.T) {
handler.Eval(context) handler.Eval(context)
So(context.Firing, ShouldEqual, false) So(context.Firing, ShouldEqual, false)
So(context.FiringEval, ShouldEqual, "[[true AND false] AND true] = false") So(context.ConditionEvals, ShouldEqual, "[[true AND false] AND true] = false")
}) })
Convey("Show return true if a condition is passing with nested OR operator", func() { Convey("Show return true if a condition is passing with nested OR operator", func() {
...@@ -125,7 +125,7 @@ func TestAlertingExecutor(t *testing.T) { ...@@ -125,7 +125,7 @@ func TestAlertingExecutor(t *testing.T) {
handler.Eval(context) handler.Eval(context)
So(context.Firing, ShouldEqual, true) So(context.Firing, ShouldEqual, true)
So(context.FiringEval, ShouldEqual, "[[true OR false] OR true] = true") So(context.ConditionEvals, ShouldEqual, "[[true OR false] OR true] = true")
}) })
}) })
} }
...@@ -38,23 +38,23 @@ ...@@ -38,23 +38,23 @@
<h5 class="section-heading">Conditions</h5> <h5 class="section-heading">Conditions</h5>
<div class="gf-form-inline" ng-repeat="conditionModel in ctrl.conditionModels"> <div class="gf-form-inline" ng-repeat="conditionModel in ctrl.conditionModels">
<div class="gf-form"> <div class="gf-form">
<metric-segment-model css-class="query-keyword" ng-if="$index" property="conditionModel.operator.type" options="ctrl.evalOperators" custom="false"></metric-segment-model> <metric-segment-model css-class="query-keyword width-5" ng-if="$index" property="conditionModel.operator.type" options="ctrl.evalOperators" custom="false"></metric-segment-model>
<span class="gf-form-label query-keyword width-5" ng-if="$index===0">WHEN</span> <span class="gf-form-label query-keyword width-5" ng-if="$index===0">WHEN</span>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<query-part-editor class="gf-form-label query-part" part="conditionModel.reducerPart" handle-event="ctrl.handleReducerPartEvent(conditionModel, $event)"> <query-part-editor class="gf-form-label query-part width-5" part="conditionModel.reducerPart" handle-event="ctrl.handleReducerPartEvent(conditionModel, $event)">
</query-part-editor> </query-part-editor>
<span class="gf-form-label query-keyword">OF</span> <span class="gf-form-label query-keyword">OF</span>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<query-part-editor class="gf-form-label query-part" part="conditionModel.queryPart" handle-event="ctrl.handleQueryPartEvent(conditionModel, $event)"> <query-part-editor class="gf-form-label query-part width-10" part="conditionModel.queryPart" handle-event="ctrl.handleQueryPartEvent(conditionModel, $event)">
</query-part-editor> </query-part-editor>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<metric-segment-model property="conditionModel.evaluator.type" options="ctrl.evalFunctions" custom="false" css-class="query-keyword" on-change="ctrl.evaluatorTypeChanged(conditionModel.evaluator)"></metric-segment-model> <metric-segment-model property="conditionModel.evaluator.type" options="ctrl.evalFunctions" custom="false" css-class="query-keyword" on-change="ctrl.evaluatorTypeChanged(conditionModel.evaluator)"></metric-segment-model>
<input class="gf-form-input max-width-7" type="number" step="any" ng-hide="conditionModel.evaluator.params.length === 0" ng-model="conditionModel.evaluator.params[0]" ng-change="ctrl.evaluatorParamsChanged()"></input> <input class="gf-form-input max-width-9" type="number" step="any" ng-hide="conditionModel.evaluator.params.length === 0" ng-model="conditionModel.evaluator.params[0]" ng-change="ctrl.evaluatorParamsChanged()"></input>
<label class="gf-form-label query-keyword" ng-show="conditionModel.evaluator.params.length === 2">TO</label> <label class="gf-form-label query-keyword" ng-show="conditionModel.evaluator.params.length === 2">TO</label>
<input class="gf-form-input max-width-7" type="number" step="any" ng-if="conditionModel.evaluator.params.length === 2" ng-model="conditionModel.evaluator.params[1]" ng-change="ctrl.evaluatorParamsChanged()"></input> <input class="gf-form-input max-width-9" type="number" step="any" ng-if="conditionModel.evaluator.params.length === 2" ng-model="conditionModel.evaluator.params[1]" ng-change="ctrl.evaluatorParamsChanged()"></input>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label"> <label class="gf-form-label">
......
...@@ -34,6 +34,9 @@ export class DashboardRow { ...@@ -34,6 +34,9 @@ export class DashboardRow {
getSaveModel() { getSaveModel() {
assignModelProperties(this.model, this, this.defaults); assignModelProperties(this.model, this, this.defaults);
// remove properties that dont server persisted purpose
delete this.model.isNew;
return this.model; return this.model;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment