mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
208 lines
5.5 KiB
Go
208 lines
5.5 KiB
Go
package alerting
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"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"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
)
|
|
|
|
type NotifierImpl struct {
|
|
log log.Logger
|
|
getNotifications func(orgId int64, notificationGroups []int64) []*Notification
|
|
}
|
|
|
|
func NewNotifier() *NotifierImpl {
|
|
log := log.New("alerting.notifier")
|
|
return &NotifierImpl{
|
|
log: log,
|
|
getNotifications: buildGetNotifiers(log),
|
|
}
|
|
}
|
|
|
|
func (n NotifierImpl) ShouldDispath(alertResult *AlertResult, notifier *Notification) bool {
|
|
warn := alertResult.State == alertstates.Warn && notifier.SendWarning
|
|
crit := alertResult.State == alertstates.Critical && notifier.SendCritical
|
|
return (warn || crit) || alertResult.State == alertstates.Ok
|
|
}
|
|
|
|
func (n *NotifierImpl) Notify(alertResult *AlertResult) {
|
|
notifiers := n.getNotifications(alertResult.AlertJob.Rule.OrgId, alertResult.AlertJob.Rule.NotificationGroups)
|
|
|
|
for _, notifier := range notifiers {
|
|
if n.ShouldDispath(alertResult, notifier) {
|
|
n.log.Info("Sending notification", "state", alertResult.State, "type", notifier.Type)
|
|
go notifier.Notifierr.Dispatch(alertResult)
|
|
}
|
|
}
|
|
}
|
|
|
|
type Notification struct {
|
|
Name string
|
|
Type string
|
|
SendWarning bool
|
|
SendCritical bool
|
|
|
|
Notifierr NotificationDispatcher
|
|
}
|
|
|
|
type EmailNotifier struct {
|
|
To string
|
|
log log.Logger
|
|
}
|
|
|
|
func (this *EmailNotifier) Dispatch(alertResult *AlertResult) {
|
|
this.log.Info("Sending email")
|
|
grafanaUrl := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
|
|
if setting.AppSubUrl != "" {
|
|
grafanaUrl += "/" + setting.AppSubUrl
|
|
}
|
|
|
|
query := &m.GetDashboardsQuery{
|
|
DashboardIds: []int64{alertResult.AlertJob.Rule.DashboardId},
|
|
}
|
|
|
|
if err := bus.Dispatch(query); err != nil {
|
|
this.log.Error("Failed to load dashboard", "error", err)
|
|
return
|
|
}
|
|
|
|
if len(query.Result) != 1 {
|
|
this.log.Error("Can only support one dashboard", "result", len(query.Result))
|
|
return
|
|
}
|
|
|
|
dashboard := query.Result[0]
|
|
|
|
panelId := strconv.Itoa(int(alertResult.AlertJob.Rule.PanelId))
|
|
|
|
//TODO: get from alertrule and transforms to seconds
|
|
from := "1466169458375"
|
|
to := "1466171258375"
|
|
|
|
renderUrl := fmt.Sprintf("%s/render/dashboard-solo/db/%s?from=%s&to=%s&panelId=%s&width=1000&height=500", grafanaUrl, dashboard.Slug, from, to, panelId)
|
|
cmd := &m.SendEmailCommand{
|
|
Data: map[string]interface{}{
|
|
"Name": "Name",
|
|
"State": alertResult.State,
|
|
"Description": alertResult.Description,
|
|
"TriggeredAlerts": alertResult.TriggeredAlerts,
|
|
"DashboardLink": grafanaUrl + "/dashboard/db/" + dashboard.Slug,
|
|
"AlertPageUrl": grafanaUrl + "/alerting",
|
|
"DashboardImage": renderUrl,
|
|
},
|
|
To: []string{this.To},
|
|
Template: "alert_notification.html",
|
|
}
|
|
|
|
err := bus.Dispatch(cmd)
|
|
if err != nil {
|
|
this.log.Error("Could not send alert notification as email", "error", err)
|
|
}
|
|
}
|
|
|
|
type WebhookNotifier struct {
|
|
Url string
|
|
User string
|
|
Password string
|
|
log log.Logger
|
|
}
|
|
|
|
func (this *WebhookNotifier) Dispatch(alertResult *AlertResult) {
|
|
this.log.Info("Sending webhook")
|
|
|
|
bodyJSON := simplejson.New()
|
|
bodyJSON.Set("name", alertResult.AlertJob.Rule.Name)
|
|
bodyJSON.Set("state", alertResult.State)
|
|
bodyJSON.Set("trigged", alertResult.TriggeredAlerts)
|
|
|
|
body, _ := bodyJSON.MarshalJSON()
|
|
|
|
cmd := &m.SendWebhook{
|
|
Url: this.Url,
|
|
User: this.User,
|
|
Password: this.Password,
|
|
Body: string(body),
|
|
}
|
|
|
|
bus.Dispatch(cmd)
|
|
}
|
|
|
|
type NotificationDispatcher interface {
|
|
Dispatch(alertResult *AlertResult)
|
|
}
|
|
|
|
func buildGetNotifiers(log log.Logger) func(orgId int64, notificationGroups []int64) []*Notification {
|
|
return func(orgId int64, notificationGroups []int64) []*Notification {
|
|
query := &m.GetAlertNotificationQuery{
|
|
OrgID: orgId,
|
|
Ids: notificationGroups,
|
|
IncludeAlwaysExecute: true,
|
|
}
|
|
err := bus.Dispatch(query)
|
|
if err != nil {
|
|
log.Error("Failed to read notifications", "error", err)
|
|
}
|
|
|
|
var result []*Notification
|
|
for _, notification := range query.Result {
|
|
not, err := NewNotificationFromDBModel(notification)
|
|
if err == nil {
|
|
result = append(result, not)
|
|
} else {
|
|
log.Error("Failed to read notification model", "error", err)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
}
|
|
|
|
func NewNotificationFromDBModel(model *m.AlertNotification) (*Notification, error) {
|
|
notifier, err := createNotifier(model.Type, model.Settings)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Notification{
|
|
Name: model.Name,
|
|
Type: model.Type,
|
|
Notifierr: notifier,
|
|
SendCritical: model.Settings.Get("sendCrit").MustBool(),
|
|
SendWarning: model.Settings.Get("sendWarn").MustBool(),
|
|
}, nil
|
|
}
|
|
|
|
var createNotifier = func(notificationType string, settings *simplejson.Json) (NotificationDispatcher, error) {
|
|
if notificationType == "email" {
|
|
to := settings.Get("to").MustString()
|
|
|
|
if to == "" {
|
|
return nil, fmt.Errorf("Could not find to propertie in settings")
|
|
}
|
|
|
|
return &EmailNotifier{
|
|
To: to,
|
|
log: log.New("alerting.notification.email"),
|
|
}, nil
|
|
}
|
|
|
|
url := settings.Get("url").MustString()
|
|
if url == "" {
|
|
return nil, fmt.Errorf("Could not find url propertie in settings")
|
|
}
|
|
|
|
return &WebhookNotifier{
|
|
Url: url,
|
|
User: settings.Get("user").MustString(),
|
|
Password: settings.Get("password").MustString(),
|
|
log: log.New("alerting.notification.webhook"),
|
|
}, nil
|
|
}
|