diff --git a/pkg/api/alerting.go b/pkg/api/alerting.go index 63a080a74d2..80b5108bbad 100644 --- a/pkg/api/alerting.go +++ b/pkg/api/alerting.go @@ -215,8 +215,13 @@ func DeleteAlertNotification(c *middleware.Context) Response { } func GetAlertHistory(c *middleware.Context) Response { + alertId, err := getAlertIdForRequest(c) + if err != nil { + return ApiError(400, "Invalid request", err) + } + query := &annotations.ItemQuery{ - AlertId: c.ParamsInt64("alertId"), + AlertId: alertId, Type: annotations.AlertType, OrgId: c.OrgId, Limit: c.QueryInt64("limit"), @@ -244,3 +249,34 @@ func GetAlertHistory(c *middleware.Context) Response { return Json(200, result) } + +func getAlertIdForRequest(c *middleware.Context) (int64, error) { + alertId := c.QueryInt64("alertId") + panelId := c.QueryInt64("panelId") + dashboardId := c.QueryInt64("dashboardId") + + if alertId == 0 && dashboardId == 0 && panelId == 0 { + return 0, fmt.Errorf("Missing alertId or dashboardId and panelId") + } + + if alertId == 0 { + //fetch alertId + query := models.GetAlertsQuery{ + OrgId: c.OrgId, + DashboardId: dashboardId, + PanelId: panelId, + } + + if err := bus.Dispatch(&query); err != nil { + return 0, err + } + + if len(query.Result) != 1 { + return 0, fmt.Errorf("PanelId is not unique on dashboard") + } + + alertId = query.Result[0].Id + } + + return alertId, nil +} diff --git a/pkg/api/api.go b/pkg/api/api.go index 966f950ee53..132c609dde4 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -254,7 +254,7 @@ func Register(r *macaron.Macaron) { r.Get("/", wrap(GetAlerts)) }) - r.Get("/alert-history/:alertId", ValidateOrgAlert, wrap(GetAlertHistory)) + r.Get("/alert-history", wrap(GetAlertHistory)) r.Get("/alert-notifications", wrap(GetAlertNotifications)) diff --git a/pkg/api/dtos/alerting.go b/pkg/api/dtos/alerting.go index c6cafddead0..d5fbb2c3a9f 100644 --- a/pkg/api/dtos/alerting.go +++ b/pkg/api/dtos/alerting.go @@ -55,7 +55,7 @@ type EvalMatch struct { type AlertHistory struct { AlertId int64 `json:"alertId"` - NewState string `json:"netState"` + NewState string `json:"newState"` Timestamp time.Time `json:"timestamp"` Title string `json:"title"` Text string `json:"text"` diff --git a/pkg/services/alerting/result_handler.go b/pkg/services/alerting/result_handler.go index 09c77c8edd7..eca10f87494 100644 --- a/pkg/services/alerting/result_handler.go +++ b/pkg/services/alerting/result_handler.go @@ -4,6 +4,7 @@ import ( "time" "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/metrics" m "github.com/grafana/grafana/pkg/models" @@ -65,6 +66,7 @@ func (handler *DefaultResultHandler) Handle(ctx *EvalContext) { NewState: string(ctx.Rule.State), PrevState: string(oldState), Timestamp: time.Now(), + Data: simplejson.NewFromAny(ctx.EvalMatches), } annotationRepo := annotations.GetRepository() diff --git a/public/app/features/alerting/alert_tab_ctrl.ts b/public/app/features/alerting/alert_tab_ctrl.ts index 2f222802438..0c42c2dbe7e 100644 --- a/public/app/features/alerting/alert_tab_ctrl.ts +++ b/public/app/features/alerting/alert_tab_ctrl.ts @@ -5,6 +5,7 @@ import {ThresholdMapper} from './threshold_mapper'; import {QueryPart} from 'app/core/components/query_part/query_part'; import alertDef from './alert_def'; import config from 'app/core/config'; +import moment from 'moment'; export class AlertTabCtrl { panel: any; @@ -22,6 +23,7 @@ export class AlertTabCtrl { alertNotifications; error: string; appSubUrl: string; + alertHistory: any; /** @ngInject */ constructor(private $scope, @@ -60,6 +62,7 @@ export class AlertTabCtrl { // build notification model this.notifications = []; this.alertNotifications = []; + this.alertHistory = []; return this.backendSrv.get('/api/alert-notifications').then(res => { this.notifications = res; @@ -71,6 +74,19 @@ export class AlertTabCtrl { this.alertNotifications.push(model); } }); + }).then(() => { + this.backendSrv.get(`/api/alert-history?dashboardId=${this.panelCtrl.dashboard.id}&panelId=${this.panel.id}`).then(res => { + this.alertHistory = _.map(res, (ah) => { + ah.time = moment(ah.timestamp).format('MMM D, YYYY HH:mm:ss'); + ah.stateModel = alertDef.getStateDisplayModel(ah.newState); + + ah.metrics = _.map(ah.data, (ev) => { + return ev.Metric + "=" + ev.Value; + }).join(', '); + + return ah; + }); + }); }); } diff --git a/public/app/features/alerting/partials/alert_tab.html b/public/app/features/alerting/partials/alert_tab.html index a386d23945b..7a98cf38a31 100644 --- a/public/app/features/alerting/partials/alert_tab.html +++ b/public/app/features/alerting/partials/alert_tab.html @@ -122,6 +122,28 @@ + +