feat(alerting): lots of progress on notifications, refactored them out to their own package, restored webhook notitication and added slack notification

This commit is contained in:
Torkel Ödegaard
2016-07-27 12:09:55 +02:00
parent 77c66a88d9
commit ae5f8a76d9
16 changed files with 416 additions and 116 deletions

View File

@@ -0,0 +1,10 @@
package notifiers
type NotifierBase struct {
Name string
Type string
}
func (n *NotifierBase) GetType() string {
return n.Type
}

View File

@@ -0,0 +1,20 @@
package notifiers
import (
"fmt"
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
func getRuleLink(rule *alerting.AlertRule) (string, error) {
slugQuery := &m.GetDashboardSlugByIdQuery{Id: rule.DashboardId}
if err := bus.Dispatch(slugQuery); err != nil {
return "", err
}
ruleLink := fmt.Sprintf("%sdashboard/db/%s?fullscreen&edit&tab=alert&panelId=%d", setting.AppUrl, slugQuery.Result, rule.PanelId)
return ruleLink, nil
}

View File

@@ -0,0 +1,62 @@
package notifiers
import (
"strings"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/log"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
func init() {
alerting.RegisterNotifier("email", NewEmailNotifier)
}
type EmailNotifier struct {
NotifierBase
Addresses []string
log log.Logger
}
func NewEmailNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
addressesString := model.Settings.Get("addresses").MustString()
if addressesString == "" {
return nil, alerting.AlertValidationError{Reason: "Could not find addresses in settings"}
}
return &EmailNotifier{
NotifierBase: NotifierBase{
Name: model.Name,
Type: model.Type,
},
Addresses: strings.Split(addressesString, "\n"),
log: log.New("alerting.notifier.email"),
}, nil
}
func (this *EmailNotifier) Notify(context *alerting.AlertResultContext) {
this.log.Info("Sending alert notification to", "addresses", this.Addresses)
ruleLink, err := getRuleLink(context.Rule)
if err != nil {
this.log.Error("Failed get rule link", "error", err)
return
}
cmd := &m.SendEmailCommand{
Data: map[string]interface{}{
"RuleState": context.Rule.State,
"RuleName": context.Rule.Name,
"Severity": context.Rule.Severity,
"RuleLink": ruleLink,
},
To: this.Addresses,
Template: "alert_notification.html",
}
if err := bus.Dispatch(cmd); err != nil {
this.log.Error("Failed to send alert notification email", "error", err)
}
}

View File

@@ -0,0 +1,52 @@
package notifiers
import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
m "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
func TestEmailNotifier(t *testing.T) {
Convey("Email notifier tests", t, func() {
Convey("Parsing alert notification from settings", func() {
Convey("empty settings should return error", func() {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
model := &m.AlertNotification{
Name: "ops",
Type: "email",
Settings: settingsJSON,
}
_, err := NewEmailNotifier(model)
So(err, ShouldNotBeNil)
})
Convey("from settings", func() {
json := `
{
"addresses": "ops@grafana.org"
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
model := &m.AlertNotification{
Name: "ops",
Type: "email",
Settings: settingsJSON,
}
not, err := NewEmailNotifier(model)
emailNotifier := not.(*EmailNotifier)
So(err, ShouldBeNil)
So(emailNotifier.Name, ShouldEqual, "ops")
So(emailNotifier.Type, ShouldEqual, "email")
So(emailNotifier.Addresses[0], ShouldEqual, "ops@grafana.org")
})
})
})
}

View File

@@ -0,0 +1,66 @@
package notifiers
import (
"fmt"
"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"
)
func init() {
alerting.RegisterNotifier("slack", NewSlackNotifier)
}
func NewSlackNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.AlertValidationError{Reason: "Could not find url property in settings"}
}
return &SlackNotifier{
NotifierBase: NotifierBase{
Name: model.Name,
Type: model.Type,
},
Url: url,
log: log.New("alerting.notifier.slack"),
}, nil
}
type SlackNotifier struct {
NotifierBase
Url string
log log.Logger
}
func (this *SlackNotifier) Notify(context *alerting.AlertResultContext) {
this.log.Info("Executing slack notification", "ruleId", context.Rule.Id, "notification", this.Name)
rule := context.Rule
ruleLink, err := getRuleLink(rule)
if err != nil {
this.log.Error("Failed get rule link", "error", err)
return
}
stateText := string(rule.Severity)
if !context.Firing {
stateText = "ok"
}
text := fmt.Sprintf("[%s]: <%s|%s>", stateText, ruleLink, rule.Name)
body := simplejson.New()
body.Set("text", text)
data, _ := body.MarshalJSON()
cmd := &m.SendWebhook{Url: this.Url, Body: string(data)}
if err := bus.Dispatch(cmd); err != nil {
this.log.Error("Failed to send slack notification", "error", err, "webhook", this.Name)
}
}

View File

@@ -0,0 +1,61 @@
package notifiers
import (
"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"
)
func init() {
alerting.RegisterNotifier("webhook", NewWebHookNotifier)
}
func NewWebHookNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.AlertValidationError{Reason: "Could not find url property in settings"}
}
return &WebhookNotifier{
NotifierBase: NotifierBase{
Name: model.Name,
Type: model.Type,
},
Url: url,
User: model.Settings.Get("user").MustString(),
Password: model.Settings.Get("password").MustString(),
log: log.New("alerting.notifier.webhook"),
}, nil
}
type WebhookNotifier struct {
NotifierBase
Url string
User string
Password string
log log.Logger
}
func (this *WebhookNotifier) Notify(context *alerting.AlertResultContext) {
this.log.Info("Sending webhook")
bodyJSON := simplejson.New()
bodyJSON.Set("name", context.Rule.Name)
bodyJSON.Set("firing", context.Firing)
bodyJSON.Set("severity", context.Rule.Severity)
body, _ := bodyJSON.MarshalJSON()
cmd := &m.SendWebhook{
Url: this.Url,
User: this.User,
Password: this.Password,
Body: string(body),
}
if err := bus.Dispatch(cmd); err != nil {
this.log.Error("Failed to send webhook", "error", err, "webhook", this.Name)
}
}

View File

@@ -0,0 +1,52 @@
package notifiers
import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
m "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
func TestWebhookNotifier(t *testing.T) {
Convey("Webhook notifier tests", t, func() {
Convey("Parsing alert notification from settings", func() {
Convey("empty settings should return error", func() {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
model := &m.AlertNotification{
Name: "ops",
Type: "email",
Settings: settingsJSON,
}
_, err := NewWebHookNotifier(model)
So(err, ShouldNotBeNil)
})
Convey("from settings", func() {
json := `
{
"url": "http://google.com"
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
model := &m.AlertNotification{
Name: "ops",
Type: "email",
Settings: settingsJSON,
}
not, err := NewWebHookNotifier(model)
emailNotifier := not.(*WebhookNotifier)
So(err, ShouldBeNil)
So(emailNotifier.Name, ShouldEqual, "ops")
So(emailNotifier.Type, ShouldEqual, "email")
So(emailNotifier.Url, ShouldEqual, "http://google.com")
})
})
})
}