Browse Source

feat(alerting): add support to keep last state on no data

closes #6332
bergquist 9 years ago
parent
commit
ad56f67ad1

+ 2 - 0
pkg/models/alert.go

@@ -15,6 +15,8 @@ const (
 	AlertStatePaused    AlertStateType = "paused"
 	AlertStateAlerting  AlertStateType = "alerting"
 	AlertStateOK        AlertStateType = "ok"
+
+	KeepLastAlertState AlertStateType = "keep_last"
 )
 
 func (s AlertStateType) IsValid() bool {

+ 10 - 2
pkg/services/alerting/result_handler.go

@@ -41,7 +41,6 @@ func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error {
 		evalContext.Rule.State = m.AlertStateAlerting
 		annotationData = simplejson.NewFromAny(evalContext.EvalMatches)
 	} else {
-		// handle no data case
 		if evalContext.NoDataFound {
 			evalContext.Rule.State = evalContext.Rule.NoDataState
 		} else {
@@ -50,7 +49,7 @@ func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error {
 	}
 
 	countStateResult(evalContext.Rule.State)
-	if evalContext.Rule.State != oldState {
+	if handler.shouldUpdateAlertState(evalContext, oldState) {
 		handler.log.Info("New state change", "alertId", evalContext.Rule.Id, "newState", evalContext.Rule.State, "oldState", oldState)
 
 		cmd := &m.SetAlertStateCommand{
@@ -91,6 +90,15 @@ func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error {
 	return nil
 }
 
+func (handler *DefaultResultHandler) shouldUpdateAlertState(evalContext *EvalContext, oldState m.AlertStateType) bool {
+	if evalContext.NoDataFound && evalContext.Rule.NoDataState == m.KeepLastAlertState {
+		evalContext.Rule.State = oldState
+		return false
+	}
+
+	return evalContext.Rule.State != oldState
+}
+
 func countStateResult(state m.AlertStateType) {
 	switch state {
 	case m.AlertStateAlerting:

+ 28 - 56
pkg/services/alerting/result_handler_test.go

@@ -1,58 +1,30 @@
 package alerting
 
-// import (
-// 	"testing"
-// 	"time"
-//
-// 	"github.com/grafana/grafana/pkg/bus"
-// 	m "github.com/grafana/grafana/pkg/models"
-// 	"github.com/grafana/grafana/pkg/services/alerting/alertstates"
-//
-// 	. "github.com/smartystreets/goconvey/convey"
-// )
-//
-// func TestAlertResultHandler(t *testing.T) {
-// 	Convey("Test result Handler", t, func() {
-// 		resultHandler := ResultHandlerImpl{}
-// 		mockResult := &AlertResultContext{
-// 			Triggered: false,
-// 			Rule: &AlertRule{
-// 				Id:    1,
-// 				OrgId 1,
-// 			},
-// 		}
-// 		mockAlertState := &m.AlertState{}
-// 		bus.ClearBusHandlers()
-// 		bus.AddHandler("test", func(query *m.GetLastAlertStateQuery) error {
-// 			query.Result = mockAlertState
-// 			return nil
-// 		})
-//
-// 		Convey("Should update", func() {
-//
-// 			Convey("when no earlier alert state", func() {
-// 				mockAlertState = nil
-// 				So(resultHandler.shouldUpdateState(mockResult), ShouldBeTrue)
-// 			})
-//
-// 			Convey("alert state have changed", func() {
-// 				mockAlertState = &m.AlertState{
-// 					State: alertstates.Critical,
-// 				}
-// 				mockResult.Triggered = false
-// 				So(resultHandler.shouldUpdateState(mockResult), ShouldBeTrue)
-// 			})
-//
-// 			Convey("last alert state was 15min ago", func() {
-// 				now := time.Now()
-// 				mockAlertState = &m.AlertState{
-// 					State:   alertstates.Critical,
-// 					Created: now.Add(time.Minute * -30),
-// 				}
-// 				mockResult.Triggered = true
-// 				mockResult.StartTime = time.Now()
-// 				So(resultHandler.shouldUpdateState(mockResult), ShouldBeTrue)
-// 			})
-// 		})
-// 	})
-// }
+import (
+	"context"
+	"testing"
+
+	"github.com/grafana/grafana/pkg/models"
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestAlertResultHandler(t *testing.T) {
+	Convey("Test result Handler", t, func() {
+
+		handler := NewResultHandler()
+		evalContext := NewEvalContext(context.TODO(), &Rule{})
+
+		Convey("Should update", func() {
+
+			Convey("when no earlier alert state", func() {
+				oldState := models.AlertStateOK
+
+				evalContext.Rule.State = models.AlertStateAlerting
+				evalContext.Rule.NoDataState = models.KeepLastAlertState
+				evalContext.NoDataFound = true
+
+				So(handler.shouldUpdateAlertState(evalContext, oldState), ShouldBeFalse)
+			})
+		})
+	})
+}

+ 1 - 0
public/app/features/alerting/alert_def.ts

@@ -40,6 +40,7 @@ var noDataModes = [
   {text: 'OK', value: 'ok'},
   {text: 'Alerting', value: 'alerting'},
   {text: 'No Data', value: 'no_data'},
+  {text: 'Keep Last', value: 'keep_last'},
 ];
 
 function createReducerPart(model) {