diff --git a/pkg/api/dtos/alerting.go b/pkg/api/dtos/alerting.go index 2276d87e545..f503b330799 100644 --- a/pkg/api/dtos/alerting.go +++ b/pkg/api/dtos/alerting.go @@ -50,3 +50,8 @@ type AlertTestResultLog struct { Message string `json:"message"` Data interface{} `json:"data"` } + +type AlertEvent struct { + Metric string `json:"metric"` + Value float64 `json:"value"` +} diff --git a/pkg/models/alert_state.go b/pkg/models/alert_state.go index 679da91f22f..b32a0dc8aec 100644 --- a/pkg/models/alert_state.go +++ b/pkg/models/alert_state.go @@ -29,11 +29,10 @@ func (this *UpdateAlertStateCommand) IsValidState() bool { // Commands type UpdateAlertStateCommand struct { - AlertId int64 `json:"alertId" binding:"Required"` - OrgId int64 `json:"orgId" binding:"Required"` - State string `json:"state" binding:"Required"` - Info string `json:"info"` - TriggeredAlerts *simplejson.Json `json:"triggeredAlerts"` + AlertId int64 `json:"alertId" binding:"Required"` + OrgId int64 `json:"orgId" binding:"Required"` + State string `json:"state" binding:"Required"` + Info string `json:"info"` Result *Alert } diff --git a/pkg/services/alerting/alert_rule.go b/pkg/services/alerting/alert_rule.go index e9942e76a8a..138884276bd 100644 --- a/pkg/services/alerting/alert_rule.go +++ b/pkg/services/alerting/alert_rule.go @@ -70,11 +70,11 @@ func NewAlertRuleFromDBModel(ruleDef *m.Alert) (*AlertRule, error) { } } - for _, condition := range ruleDef.Settings.Get("conditions").MustArray() { + for index, condition := range ruleDef.Settings.Get("conditions").MustArray() { conditionModel := simplejson.NewFromAny(condition) switch conditionModel.Get("type").MustString() { case "query": - queryCondition, err := NewQueryCondition(conditionModel) + queryCondition, err := NewQueryCondition(conditionModel, index) if err != nil { return nil, err } diff --git a/pkg/services/alerting/conditions.go b/pkg/services/alerting/conditions.go index a77cfdaf686..a72eff3a7a6 100644 --- a/pkg/services/alerting/conditions.go +++ b/pkg/services/alerting/conditions.go @@ -11,6 +11,7 @@ import ( ) type QueryCondition struct { + Index int Query AlertQuery Reducer QueryReducer Evaluator AlertEvaluator @@ -27,7 +28,18 @@ func (c *QueryCondition) Eval(context *AlertResultContext) { for _, series := range seriesList { reducedValue := c.Reducer.Reduce(series) pass := c.Evaluator.Eval(series, reducedValue) + + if context.IsTestRun { + context.Logs = append(context.Logs, &AlertResultLogEntry{ + Message: fmt.Sprintf("Condition[%d]: Eval: %v, Metric: %s, Value: %1.3f", c.Index, pass, series.Name, reducedValue), + }) + } + if pass { + context.Events = append(context.Events, &AlertEvent{ + Metric: series.Name, + Value: reducedValue, + }) context.Triggered = true break } @@ -61,7 +73,7 @@ func (c *QueryCondition) executeQuery(context *AlertResultContext) (tsdb.TimeSer if context.IsTestRun { context.Logs = append(context.Logs, &AlertResultLogEntry{ - Message: "Query Condition Query Result", + Message: fmt.Sprintf("Condition[%d]: Query Result", c.Index), Data: v.Series, }) } @@ -93,8 +105,9 @@ func (c *QueryCondition) getRequestForAlertRule(datasource *m.DataSource) *tsdb. return req } -func NewQueryCondition(model *simplejson.Json) (*QueryCondition, error) { +func NewQueryCondition(model *simplejson.Json, index int) (*QueryCondition, error) { condition := QueryCondition{} + condition.Index = index condition.HandleRequest = tsdb.HandleRequest queryJson := model.Get("query") diff --git a/pkg/services/alerting/conditions_test.go b/pkg/services/alerting/conditions_test.go index a9f340c37a8..89a50cedd20 100644 --- a/pkg/services/alerting/conditions_test.go +++ b/pkg/services/alerting/conditions_test.go @@ -60,7 +60,7 @@ func (ctx *queryConditionTestContext) exec() { }`)) So(err, ShouldBeNil) - condition, err := NewQueryCondition(jsonModel) + condition, err := NewQueryCondition(jsonModel, 0) So(err, ShouldBeNil) condition.HandleRequest = func(req *tsdb.Request) (*tsdb.Response, error) { diff --git a/pkg/services/alerting/handler.go b/pkg/services/alerting/handler.go index 77218d473ff..dbc1deb8090 100644 --- a/pkg/services/alerting/handler.go +++ b/pkg/services/alerting/handler.go @@ -33,7 +33,7 @@ func (e *HandlerImpl) Execute(context *AlertResultContext) { context.EndTime = time.Now() e.log.Debug("Job Execution timeout", "alertId", context.Rule.Id) case <-context.DoneChan: - e.log.Debug("Job Execution done", "timing", context.GetDurationSeconds(), "alertId", context.Rule.Id) + e.log.Debug("Job Execution done", "timing", context.GetDurationSeconds(), "alertId", context.Rule.Id, "triggered", context.Triggered) } } diff --git a/pkg/services/alerting/models.go b/pkg/services/alerting/models.go index 837111b7f7a..598dd4fcdf4 100644 --- a/pkg/services/alerting/models.go +++ b/pkg/services/alerting/models.go @@ -30,7 +30,7 @@ func (aj *AlertJob) IncRetry() { type AlertResultContext struct { Triggered bool IsTestRun bool - Details []*AlertResultDetail + Events []*AlertEvent Logs []*AlertResultLogEntry Error error Description string @@ -51,6 +51,7 @@ func NewAlertResultContext(rule *AlertRule) *AlertResultContext { StartTime: time.Now(), Rule: rule, Logs: make([]*AlertResultLogEntry, 0), + Events: make([]*AlertEvent, 0), DoneChan: make(chan bool, 1), CancelChan: make(chan bool, 1), log: log.New("alerting.engine"), @@ -62,7 +63,7 @@ type AlertResultLogEntry struct { Data interface{} } -type AlertResultDetail struct { +type AlertEvent struct { Value float64 Metric string State string diff --git a/pkg/services/alerting/result_handler.go b/pkg/services/alerting/result_handler.go index 44c7b43da8f..669f1a63ef7 100644 --- a/pkg/services/alerting/result_handler.go +++ b/pkg/services/alerting/result_handler.go @@ -4,7 +4,6 @@ import ( "time" "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/log" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting/alertstates" @@ -37,11 +36,10 @@ func (handler *ResultHandlerImpl) Handle(result *AlertResultContext) { if handler.shouldUpdateState(result, newState) { cmd := &m.UpdateAlertStateCommand{ - AlertId: result.Rule.Id, - Info: result.Description, - OrgId: result.Rule.OrgId, - State: newState, - TriggeredAlerts: simplejson.NewFromAny(result.Details), + AlertId: result.Rule.Id, + Info: result.Description, + OrgId: result.Rule.OrgId, + State: newState, } if err := bus.Dispatch(cmd); err != nil { diff --git a/pkg/services/sqlstore/alert_state.go b/pkg/services/sqlstore/alert_state.go index d335f7402a7..2d591003292 100644 --- a/pkg/services/sqlstore/alert_state.go +++ b/pkg/services/sqlstore/alert_state.go @@ -51,12 +51,11 @@ func SetNewAlertState(cmd *m.UpdateAlertStateCommand) error { sess.Id(alert.Id).Update(&alert) alertState := m.AlertState{ - AlertId: cmd.AlertId, - OrgId: cmd.OrgId, - State: cmd.State, - Info: cmd.Info, - Created: time.Now(), - TriggeredAlerts: cmd.TriggeredAlerts, + AlertId: cmd.AlertId, + OrgId: cmd.OrgId, + State: cmd.State, + Info: cmd.Info, + Created: time.Now(), } sess.Insert(&alertState) diff --git a/public/app/features/alerting/alert_log_ctrl.ts b/public/app/features/alerting/alert_log_ctrl.ts index 2727f486604..a9a3788c686 100644 --- a/public/app/features/alerting/alert_log_ctrl.ts +++ b/public/app/features/alerting/alert_log_ctrl.ts @@ -22,7 +22,7 @@ export class AlertLogCtrl { loadAlertLogs(alertId: number) { this.backendSrv.get(`/api/alerts/${alertId}/states`).then(result => { this.alertLogs = _.map(result, log => { - log.iconCss = alertDef.getCssForState(log.newState); + log.iconCss = alertDef.getCssForState(log.state); log.humanTime = moment(log.created).format("YYYY-MM-DD HH:mm:ss"); return log; }); diff --git a/public/app/features/alerting/partials/alert_log.html b/public/app/features/alerting/partials/alert_log.html index 5f0ef080fe9..921f748da76 100644 --- a/public/app/features/alerting/partials/alert_log.html +++ b/public/app/features/alerting/partials/alert_log.html @@ -6,55 +6,6 @@

Alert history for {{ctrl.alert.title}}

-
-
Thresholds
-
- - - Warn level - -
- {{ctrl.alert.warnOperator}} -
-
- {{ctrl.alert.warnLevel}} -
-
-
- - - Critical level - -
- {{ctrl.alert.critOperator}} -
-
- {{ctrl.alert.critLevel}} -
-
-
- -
-
Aggregators
-
- - Aggregator - -
- {{ctrl.alert.aggregator}} -
-
-
- Query range (seconds) - {{ctrl.alert.queryRange}} -
- -
- Frequency (seconds) - {{ctrl.alert.frequency}} -
-
-
Status