mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(annotations): added support to show grafana stored annotations in graphs, #5982
This commit is contained in:
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/alerting"
|
||||
"github.com/grafana/grafana/pkg/services/annotations"
|
||||
)
|
||||
|
||||
func ValidateOrgAlert(c *middleware.Context) {
|
||||
@@ -231,42 +230,6 @@ func NotificationTest(c *middleware.Context, dto dtos.NotificationTestCommand) R
|
||||
return ApiSuccess("Test notification sent")
|
||||
}
|
||||
|
||||
func GetAlertHistory(c *middleware.Context) Response {
|
||||
alertId, err := getAlertIdForRequest(c)
|
||||
if err != nil {
|
||||
return ApiError(400, "Invalid request", err)
|
||||
}
|
||||
|
||||
query := &annotations.ItemQuery{
|
||||
AlertId: alertId,
|
||||
Type: annotations.AlertType,
|
||||
OrgId: c.OrgId,
|
||||
Limit: c.QueryInt64("limit"),
|
||||
}
|
||||
|
||||
repo := annotations.GetRepository()
|
||||
|
||||
items, err := repo.Find(query)
|
||||
if err != nil {
|
||||
return ApiError(500, "Failed to get history for alert", err)
|
||||
}
|
||||
|
||||
var result []dtos.AlertHistory
|
||||
for _, item := range items {
|
||||
result = append(result, dtos.AlertHistory{
|
||||
AlertId: item.AlertId,
|
||||
Timestamp: item.Timestamp,
|
||||
Data: item.Data,
|
||||
NewState: item.NewState,
|
||||
Text: item.Text,
|
||||
Metric: item.Metric,
|
||||
Title: item.Title,
|
||||
})
|
||||
}
|
||||
|
||||
return Json(200, result)
|
||||
}
|
||||
|
||||
func getAlertIdForRequest(c *middleware.Context) (int64, error) {
|
||||
alertId := c.QueryInt64("alertId")
|
||||
panelId := c.QueryInt64("panelId")
|
||||
|
||||
42
pkg/api/annotations.go
Normal file
42
pkg/api/annotations.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
"github.com/grafana/grafana/pkg/services/annotations"
|
||||
)
|
||||
|
||||
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"),
|
||||
}
|
||||
|
||||
repo := annotations.GetRepository()
|
||||
|
||||
items, err := repo.Find(query)
|
||||
if err != nil {
|
||||
return ApiError(500, "Failed to get annotations", err)
|
||||
}
|
||||
|
||||
result := make([]dtos.Annotation, 0)
|
||||
|
||||
for _, item := range items {
|
||||
result = append(result, dtos.Annotation{
|
||||
AlertId: item.AlertId,
|
||||
Time: item.Epoch * 1000,
|
||||
Data: item.Data,
|
||||
NewState: item.NewState,
|
||||
PrevState: item.PrevState,
|
||||
Text: item.Text,
|
||||
Metric: item.Metric,
|
||||
Title: item.Title,
|
||||
})
|
||||
}
|
||||
|
||||
return Json(200, result)
|
||||
}
|
||||
@@ -254,8 +254,6 @@ func Register(r *macaron.Macaron) {
|
||||
r.Get("/", wrap(GetAlerts))
|
||||
})
|
||||
|
||||
r.Get("/alert-history", wrap(GetAlertHistory))
|
||||
|
||||
r.Get("/alert-notifications", wrap(GetAlertNotifications))
|
||||
|
||||
r.Group("/alert-notifications", func() {
|
||||
@@ -266,6 +264,8 @@ func Register(r *macaron.Macaron) {
|
||||
r.Delete("/:notificationId", wrap(DeleteAlertNotification))
|
||||
}, reqOrgAdmin)
|
||||
|
||||
r.Get("/annotations", wrap(GetAnnotations))
|
||||
|
||||
// error test
|
||||
r.Get("/metrics/error", wrap(GenerateError))
|
||||
|
||||
|
||||
@@ -54,17 +54,6 @@ type EvalMatch struct {
|
||||
Value float64 `json:"value"`
|
||||
}
|
||||
|
||||
type AlertHistory struct {
|
||||
AlertId int64 `json:"alertId"`
|
||||
NewState string `json:"newState"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Title string `json:"title"`
|
||||
Text string `json:"text"`
|
||||
Metric string `json:"metric"`
|
||||
|
||||
Data *simplejson.Json `json:"data"`
|
||||
}
|
||||
|
||||
type NotificationTestCommand struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
|
||||
15
pkg/api/dtos/annotations.go
Normal file
15
pkg/api/dtos/annotations.go
Normal file
@@ -0,0 +1,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"`
|
||||
|
||||
Data *simplejson.Json `json:"data"`
|
||||
}
|
||||
@@ -105,6 +105,7 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
|
||||
grafanaDatasourceMeta, _ := plugins.DataSources["grafana"]
|
||||
datasources["-- Grafana --"] = map[string]interface{}{
|
||||
"type": "grafana",
|
||||
"name": "-- Grafana --",
|
||||
"meta": grafanaDatasourceMeta,
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@ func (c *EvalContext) GetStateModel() *StateDescription {
|
||||
default:
|
||||
panic("Unknown rule state " + c.Rule.State)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (a *EvalContext) GetDurationMs() float64 {
|
||||
|
||||
@@ -73,7 +73,7 @@ func (handler *DefaultResultHandler) Handle(ctx *EvalContext) {
|
||||
Text: ctx.GetStateModel().Text,
|
||||
NewState: string(ctx.Rule.State),
|
||||
PrevState: string(oldState),
|
||||
Timestamp: time.Now(),
|
||||
Epoch: time.Now().Unix(),
|
||||
Data: annotationData,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
package annotations
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
)
|
||||
import "github.com/grafana/grafana/pkg/components/simplejson"
|
||||
|
||||
type Repository interface {
|
||||
Save(item *Item) error
|
||||
@@ -13,6 +9,8 @@ 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"`
|
||||
|
||||
@@ -36,17 +34,17 @@ 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"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
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"`
|
||||
|
||||
Data *simplejson.Json `json:"data"`
|
||||
}
|
||||
|
||||
@@ -38,6 +38,9 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I
|
||||
params = append(params, query.AlertId)
|
||||
}
|
||||
|
||||
sql.WriteString(` AND epoch BETWEEN ? AND ?`)
|
||||
params = append(params, query.From, query.To)
|
||||
|
||||
if query.Type != "" {
|
||||
sql.WriteString(` AND type = ?`)
|
||||
params = append(params, string(query.Type))
|
||||
@@ -47,7 +50,7 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I
|
||||
query.Limit = 10
|
||||
}
|
||||
|
||||
sql.WriteString(fmt.Sprintf("ORDER BY timestamp DESC LIMIT %v", query.Limit))
|
||||
sql.WriteString(fmt.Sprintf("ORDER BY epoch DESC LIMIT %v", query.Limit))
|
||||
|
||||
items := make([]*annotations.Item, 0)
|
||||
if err := x.Sql(sql.String(), params...).Find(&items); err != nil {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
)
|
||||
|
||||
func addAnnotationMig(mg *Migrator) {
|
||||
|
||||
table := Table{
|
||||
Name: "annotation",
|
||||
Columns: []*Column{
|
||||
@@ -19,20 +20,22 @@ func addAnnotationMig(mg *Migrator) {
|
||||
{Name: "prev_state", Type: DB_NVarchar, Length: 25, Nullable: false},
|
||||
{Name: "new_state", Type: DB_NVarchar, Length: 25, Nullable: false},
|
||||
{Name: "data", Type: DB_Text, Nullable: false},
|
||||
{Name: "timestamp", Type: DB_DateTime, Nullable: false},
|
||||
{Name: "epoch", Type: DB_BigInt, Nullable: false},
|
||||
},
|
||||
Indices: []*Index{
|
||||
{Cols: []string{"org_id", "alert_id"}, Type: IndexType},
|
||||
{Cols: []string{"org_id", "type"}, Type: IndexType},
|
||||
{Cols: []string{"timestamp"}, Type: IndexType},
|
||||
{Cols: []string{"epoch"}, Type: IndexType},
|
||||
},
|
||||
}
|
||||
|
||||
mg.AddMigration("create annotation table v1", NewAddTableMigration(table))
|
||||
mg.AddMigration("Drop old annotation table v2", NewDropTableMigration("annotation"))
|
||||
|
||||
mg.AddMigration("create annotation table v3", NewAddTableMigration(table))
|
||||
|
||||
// create indices
|
||||
mg.AddMigration("add index annotation org_id & alert_id ", NewAddIndexMigration(table, table.Indices[0]))
|
||||
mg.AddMigration("add index annotation org_id & alert_id v2", NewAddIndexMigration(table, table.Indices[0]))
|
||||
|
||||
mg.AddMigration("add index annotation org_id & type", NewAddIndexMigration(table, table.Indices[1]))
|
||||
mg.AddMigration("add index annotation timestamp", NewAddIndexMigration(table, table.Indices[2]))
|
||||
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]))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user