diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index 4e43a7ea21e..420486047c3 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -9,11 +9,14 @@ import ( func GetAnnotations(c *middleware.Context) Response { query := &annotations.ItemQuery{ - From: c.QueryInt64("from") / 1000, - To: c.QueryInt64("to") / 1000, - Type: annotations.ItemType(c.Query("type")), - OrgId: c.OrgId, - Limit: c.QueryInt64("limit"), + From: c.QueryInt64("from") / 1000, + To: c.QueryInt64("to") / 1000, + Type: annotations.ItemType(c.Query("type")), + OrgId: c.OrgId, + AlertId: c.QueryInt64("alertId"), + DashboardId: c.QueryInt64("dashboardId"), + PanelId: c.QueryInt64("panelId"), + Limit: c.QueryInt64("limit"), } repo := annotations.GetRepository() diff --git a/pkg/api/dtos/annotations.go b/pkg/api/dtos/annotations.go index 2068b6186d2..a5d5823e1a4 100644 --- a/pkg/api/dtos/annotations.go +++ b/pkg/api/dtos/annotations.go @@ -3,13 +3,15 @@ package dtos import "github.com/grafana/grafana/pkg/components/simplejson" type Annotation struct { - AlertId int64 `json:"alertId"` - NewState string `json:"newState"` - PrevState string `json:"prevState"` - Time int64 `json:"time"` - Title string `json:"title"` - Text string `json:"text"` - Metric string `json:"metric"` + AlertId int64 `json:"alertId"` + DashboardId int64 `json:"dashboardId"` + PanelId int64 `json:"panelId"` + NewState string `json:"newState"` + PrevState string `json:"prevState"` + Time int64 `json:"time"` + Title string `json:"title"` + Text string `json:"text"` + Metric string `json:"metric"` Data *simplejson.Json `json:"data"` } diff --git a/pkg/services/alerting/result_handler.go b/pkg/services/alerting/result_handler.go index 6239a1e58d7..822d2bf8513 100644 --- a/pkg/services/alerting/result_handler.go +++ b/pkg/services/alerting/result_handler.go @@ -66,15 +66,17 @@ func (handler *DefaultResultHandler) Handle(ctx *EvalContext) { // save annotation item := annotations.Item{ - OrgId: ctx.Rule.OrgId, - Type: annotations.AlertType, - AlertId: ctx.Rule.Id, - Title: ctx.Rule.Name, - Text: ctx.GetStateModel().Text, - NewState: string(ctx.Rule.State), - PrevState: string(oldState), - Epoch: time.Now().Unix(), - Data: annotationData, + OrgId: ctx.Rule.OrgId, + DashboardId: ctx.Rule.DashboardId, + PanelId: ctx.Rule.PanelId, + Type: annotations.AlertType, + AlertId: ctx.Rule.Id, + Title: ctx.Rule.Name, + Text: ctx.GetStateModel().Text, + NewState: string(ctx.Rule.State), + PrevState: string(oldState), + Epoch: time.Now().Unix(), + Data: annotationData, } annotationRepo := annotations.GetRepository() diff --git a/pkg/services/annotations/annotations.go b/pkg/services/annotations/annotations.go index e9ef899eca9..9c0b44316dc 100644 --- a/pkg/services/annotations/annotations.go +++ b/pkg/services/annotations/annotations.go @@ -8,11 +8,13 @@ type Repository interface { } type ItemQuery struct { - OrgId int64 `json:"orgId"` - From int64 `json:"from"` - To int64 `json:"from"` - Type ItemType `json:"type"` - AlertId int64 `json:"alertId"` + OrgId int64 `json:"orgId"` + From int64 `json:"from"` + To int64 `json:"from"` + Type ItemType `json:"type"` + AlertId int64 `json:"alertId"` + DashboardId int64 `json:"dashboardId"` + PanelId int64 `json:"panelId"` Limit int64 `json:"alertId"` } @@ -34,17 +36,19 @@ const ( ) type Item struct { - Id int64 `json:"id"` - OrgId int64 `json:"orgId"` - Type ItemType `json:"type"` - Title string `json:"title"` - Text string `json:"text"` - Metric string `json:"metric"` - AlertId int64 `json:"alertId"` - UserId int64 `json:"userId"` - PrevState string `json:"prevState"` - NewState string `json:"newState"` - Epoch int64 `json:"epoch"` + Id int64 `json:"id"` + OrgId int64 `json:"orgId"` + DashboardId int64 `json:"dashboardId"` + PanelId int64 `json:"panelId"` + Type ItemType `json:"type"` + Title string `json:"title"` + Text string `json:"text"` + Metric string `json:"metric"` + AlertId int64 `json:"alertId"` + UserId int64 `json:"userId"` + PrevState string `json:"prevState"` + NewState string `json:"newState"` + Epoch int64 `json:"epoch"` Data *simplejson.Json `json:"data"` } diff --git a/pkg/services/sqlstore/annotation.go b/pkg/services/sqlstore/annotation.go index e5a5443c3bf..b604b0de44f 100644 --- a/pkg/services/sqlstore/annotation.go +++ b/pkg/services/sqlstore/annotation.go @@ -38,6 +38,21 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I params = append(params, query.AlertId) } + if query.AlertId != 0 { + sql.WriteString(` AND alert_id = ?`) + params = append(params, query.AlertId) + } + + if query.DashboardId != 0 { + sql.WriteString(` AND dashboard_id = ?`) + params = append(params, query.DashboardId) + } + + if query.PanelId != 0 { + sql.WriteString(` AND panel_id = ?`) + params = append(params, query.PanelId) + } + sql.WriteString(` AND epoch BETWEEN ? AND ?`) params = append(params, query.From, query.To) diff --git a/pkg/services/sqlstore/migrations/annotation_mig.go b/pkg/services/sqlstore/migrations/annotation_mig.go index ddb622894ac..6e2f6a680ba 100644 --- a/pkg/services/sqlstore/migrations/annotation_mig.go +++ b/pkg/services/sqlstore/migrations/annotation_mig.go @@ -13,6 +13,8 @@ func addAnnotationMig(mg *Migrator) { {Name: "org_id", Type: DB_BigInt, Nullable: false}, {Name: "alert_id", Type: DB_BigInt, Nullable: true}, {Name: "user_id", Type: DB_BigInt, Nullable: true}, + {Name: "dashboard_id", Type: DB_BigInt, Nullable: true}, + {Name: "panel_id", Type: DB_BigInt, Nullable: true}, {Name: "type", Type: DB_NVarchar, Length: 25, Nullable: false}, {Name: "title", Type: DB_Text, Nullable: false}, {Name: "text", Type: DB_Text, Nullable: false}, @@ -25,17 +27,18 @@ func addAnnotationMig(mg *Migrator) { Indices: []*Index{ {Cols: []string{"org_id", "alert_id"}, Type: IndexType}, {Cols: []string{"org_id", "type"}, Type: IndexType}, + {Cols: []string{"dashboard_id", "panel_id"}, Type: IndexType}, {Cols: []string{"epoch"}, Type: IndexType}, }, } - mg.AddMigration("Drop old annotation table v2", NewDropTableMigration("annotation")) + mg.AddMigration("Drop old annotation table v3", NewDropTableMigration("annotation")) - mg.AddMigration("create annotation table v3", NewAddTableMigration(table)) + mg.AddMigration("create annotation table v4", NewAddTableMigration(table)) // create indices - mg.AddMigration("add index annotation org_id & alert_id v2", NewAddIndexMigration(table, table.Indices[0])) - - mg.AddMigration("add index annotation org_id & type v2", NewAddIndexMigration(table, table.Indices[1])) - mg.AddMigration("add index annotation epoch", NewAddIndexMigration(table, table.Indices[2])) + mg.AddMigration("add index annotation org_id & alert_id v3", NewAddIndexMigration(table, table.Indices[0])) + mg.AddMigration("add index annotation org_id & type v3", NewAddIndexMigration(table, table.Indices[1])) + mg.AddMigration("add index annotation dashboard_id panel_id", NewAddIndexMigration(table, table.Indices[2])) + mg.AddMigration("add index annotation epoch v3", NewAddIndexMigration(table, table.Indices[3])) } diff --git a/public/app/features/annotations/annotations_srv.ts b/public/app/features/annotations/annotations_srv.ts index 9eaeccfa54c..9fbf5d7f0e6 100644 --- a/public/app/features/annotations/annotations_srv.ts +++ b/public/app/features/annotations/annotations_srv.ts @@ -14,6 +14,7 @@ export class AnnotationsSrv { constructor(private $rootScope, private $q, private datasourceSrv, + private backendSrv, private timeSrv) { $rootScope.onAppEvent('refresh', this.clearCache.bind(this), $rootScope); $rootScope.onAppEvent('dashboard-initialized', this.clearCache.bind(this), $rootScope); @@ -23,9 +24,41 @@ export class AnnotationsSrv { this.globalAnnotationsPromise = null; } - getAnnotations(dashboard) { + getAnnotations(options) { + return this.$q.all([ + this.getGlobalAnnotations(options), + this.getPanelAnnotations(options) + ]).then(allResults => { + return _.flatten(allResults); + }).catch(err => { + this.$rootScope.appEvent('alert-error', ['Annotations failed', (err.message || err)]); + }); + } + + getPanelAnnotations(options) { + var panel = options.panel; + var dashboard = options.dashboard; + + if (panel && panel.alert && panel.alert.enabled) { + return this.backendSrv.get('/api/annotations', { + from: options.range.from.valueOf(), + to: options.range.to.valueOf(), + limit: 100, + panelId: panel.id, + dashboardId: dashboard.id, + }).then(results => { + return this.translateQueryResult({iconColor: '#AA0000', name: 'panel-alert'}, results); + }); + } + + return this.$q.when([]); + } + + getGlobalAnnotations(options) { + var dashboard = options.dashboard; + if (dashboard.annotations.list.length === 0) { - return this.$q.when(null); + return this.$q.when([]); } if (this.globalAnnotationsPromise) { @@ -34,21 +67,15 @@ export class AnnotationsSrv { var annotations = _.where(dashboard.annotations.list, {enable: true}); var range = this.timeSrv.timeRange(); - var rangeRaw = this.timeSrv.timeRange(false); this.globalAnnotationsPromise = this.$q.all(_.map(annotations, annotation => { if (annotation.snapshotData) { - return this.translateQueryResult(annotation.snapshotData); + return this.translateQueryResult(annotation, annotation.snapshotData); } return this.datasourceSrv.get(annotation.datasource).then(datasource => { // issue query against data source - return datasource.annotationQuery({ - range: range, - rangeRaw: - rangeRaw, - annotation: annotation - }); + return datasource.annotationQuery({range: range, rangeRaw: range.raw, annotation: annotation}); }) .then(results => { // store response in annotation object if this is a snapshot call @@ -56,35 +83,22 @@ export class AnnotationsSrv { annotation.snapshotData = angular.copy(results); } // translate result - return this.translateQueryResult(results); + return this.translateQueryResult(annotation, results); }); - })) - .then(allResults => { - return _.flatten(allResults); - }).catch(err => { - this.$rootScope.appEvent('alert-error', ['Annotations failed', (err.message || err)]); - }); + })); return this.globalAnnotationsPromise; } - translateQueryResult(results) { - var translated = []; - + translateQueryResult(annotation, results) { for (var item of results) { - translated.push({ - annotation: item.annotation, - min: item.time, - max: item.time, - eventType: item.annotation.name, - title: item.title, - tags: item.tags, - text: item.text, - score: 1 - }); + item.source = annotation; + item.min = item.time; + item.max = item.time; + item.scope = 1; + item.eventType = annotation.name; } - - return translated; + return results; } } diff --git a/public/app/features/annotations/partials/editor.html b/public/app/features/annotations/partials/editor.html index f42e5a3a7ae..0bfc8bb2028 100644 --- a/public/app/features/annotations/partials/editor.html +++ b/public/app/features/annotations/partials/editor.html @@ -40,7 +40,7 @@