From 376d2d56bff2a04329027f6d34b673b678814357 Mon Sep 17 00:00:00 2001 From: huydx Date: Thu, 19 Jan 2017 16:25:21 +0900 Subject: [PATCH] (feature) add LINE notify to notifier --- pkg/metrics/metrics.go | 2 + pkg/models/notifications.go | 1 + pkg/services/alerting/notifiers/line.go | 94 ++++++++++++++++++++ pkg/services/alerting/notifiers/line_test.go | 50 +++++++++++ pkg/services/notifications/notifications.go | 1 + pkg/services/notifications/webhook.go | 7 ++ 6 files changed, 155 insertions(+) create mode 100644 pkg/services/alerting/notifiers/line.go create mode 100644 pkg/services/alerting/notifiers/line_test.go diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 06302484cda..1020f28f874 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -45,6 +45,7 @@ var ( M_Alerting_Notification_Sent_Email Counter M_Alerting_Notification_Sent_Webhook Counter M_Alerting_Notification_Sent_PagerDuty Counter + M_Alerting_Notification_Sent_LINE Counter M_Alerting_Notification_Sent_Victorops Counter M_Alerting_Notification_Sent_OpsGenie Counter M_Alerting_Notification_Sent_Telegram Counter @@ -118,6 +119,7 @@ func initMetricVars(settings *MetricSettings) { M_Alerting_Notification_Sent_OpsGenie = RegCounter("alerting.notifications_sent", "type", "opsgenie") M_Alerting_Notification_Sent_Telegram = RegCounter("alerting.notifications_sent", "type", "telegram") M_Alerting_Notification_Sent_Sensu = RegCounter("alerting.notifications_sent", "type", "sensu") + M_Alerting_Notification_Sent_LINE = RegCounter("alerting.notifications_sent", "type", "LINE") M_Aws_CloudWatch_GetMetricStatistics = RegCounter("aws.cloudwatch.get_metric_statistics") M_Aws_CloudWatch_ListMetrics = RegCounter("aws.cloudwatch.list_metrics") diff --git a/pkg/models/notifications.go b/pkg/models/notifications.go index 42ebda9ea44..ad7aed3bc50 100644 --- a/pkg/models/notifications.go +++ b/pkg/models/notifications.go @@ -23,6 +23,7 @@ type SendWebhookSync struct { Password string Body string HttpMethod string + HttpHeader map[string]string } type SendResetPasswordEmailCommand struct { diff --git a/pkg/services/alerting/notifiers/line.go b/pkg/services/alerting/notifiers/line.go new file mode 100644 index 00000000000..bf15c497f2c --- /dev/null +++ b/pkg/services/alerting/notifiers/line.go @@ -0,0 +1,94 @@ +package notifiers + +import ( + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/services/alerting" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/metrics" + "net/url" + "fmt" + "github.com/grafana/grafana/pkg/bus" +) + +func init() { + alerting.RegisterNotifier(&alerting.NotifierPlugin{ + Type: "LINE", + Name: "LINE", + Description: "Send notifications to LINE notify", + Factory: NewLINENotifier, + OptionsTemplate: ` +
+

LINE notify settings

+
+ Token + +
+
+`, + }) +} + +const ( + lineNotifyUrl string = "https://notify-api.line.me/api/notify" +) + +func NewLINENotifier(model *m.AlertNotification) (alerting.Notifier, error) { + token := model.Settings.Get("token").MustString() + if token == "" { + return nil, alerting.ValidationError{Reason: "Could not find token in settings"} + } + + return &LineNotifier{ + NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings), + Token: token, + log: log.New("alerting.notifier.line"), + }, nil +} + +type LineNotifier struct { + NotifierBase + Token string + log log.Logger +} + +func (this *LineNotifier) Notify(evalContext *alerting.EvalContext) error { + this.log.Info("Executing line notification", "ruleId", evalContext.Rule.Id, "notification", this.Name) + metrics.M_Alerting_Notification_Sent_LINE.Inc(1) + + var err error + switch evalContext.Rule.State { + case m.AlertStateAlerting: + err = this.createAlert(evalContext) + } + return err +} + +func (this *LineNotifier) createAlert(evalContext *alerting.EvalContext) error { + this.log.Info("Creating Line notify", "ruleId", evalContext.Rule.Id, "notification", this.Name) + ruleUrl, err := evalContext.GetRuleUrl() + if err != nil { + this.log.Error("Failed get rule link", "error", err) + return err + } + + form := url.Values{} + body := fmt.Sprintf("%s - %s\n%s", evalContext.Rule.Name, ruleUrl, evalContext.Rule.Message) + form.Add("message", body) + + cmd := &m.SendWebhookSync{ + Url: lineNotifyUrl, + HttpMethod: "POST", + HttpHeader: map[string]string{ + "Authorization": fmt.Sprintf("Bearer %s", this.Token), + "Content-Type": "application/x-www-form-urlencoded", + }, + Body: form.Encode(), + } + + if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil { + this.log.Error("Failed to send notification to LINE", "error", err, "body", string(body)) + return err + } + + return nil +} diff --git a/pkg/services/alerting/notifiers/line_test.go b/pkg/services/alerting/notifiers/line_test.go new file mode 100644 index 00000000000..8d11cc6e1bf --- /dev/null +++ b/pkg/services/alerting/notifiers/line_test.go @@ -0,0 +1,50 @@ + +package notifiers + +import ( + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestLineNotifier(t *testing.T) { + Convey("Line notifier tests", t, func() { + Convey("empty settings should return error", func() { + json := `{ }` + + settingsJSON, _ := simplejson.NewJson([]byte(json)) + model := &m.AlertNotification{ + Name: "line_testing", + Type: "line", + Settings: settingsJSON, + } + + _, err := NewLINENotifier(model) + So(err, ShouldNotBeNil) + + }) + Convey("settings should trigger incident", func() { + json := ` + { + "token": "abcdefgh0123456789" + }` + settingsJSON, _ := simplejson.NewJson([]byte(json)) + model := &m.AlertNotification{ + Name: "line_testing", + Type: "line", + Settings: settingsJSON, + } + + not, err := NewLINENotifier(model) + lineNotifier := not.(*LineNotifier) + + So(err, ShouldBeNil) + So(lineNotifier.Name, ShouldEqual, "line_testing") + So(lineNotifier.Type, ShouldEqual, "line") + So(lineNotifier.Token, ShouldEqual, "abcdefgh0123456789") + }) + + }) +} diff --git a/pkg/services/notifications/notifications.go b/pkg/services/notifications/notifications.go index c1ed9ac9e74..095ce15ef32 100644 --- a/pkg/services/notifications/notifications.go +++ b/pkg/services/notifications/notifications.go @@ -65,6 +65,7 @@ func SendWebhookSync(ctx context.Context, cmd *m.SendWebhookSync) error { Password: cmd.Password, Body: cmd.Body, HttpMethod: cmd.HttpMethod, + HttpHeader: cmd.HttpHeader, }) } diff --git a/pkg/services/notifications/webhook.go b/pkg/services/notifications/webhook.go index ac46a43f294..584d22e8b1b 100644 --- a/pkg/services/notifications/webhook.go +++ b/pkg/services/notifications/webhook.go @@ -19,6 +19,7 @@ type Webhook struct { Password string Body string HttpMethod string + HttpHeader map[string]string } var ( @@ -63,6 +64,12 @@ func sendWebRequestSync(ctx context.Context, webhook *Webhook) error { request.Header.Add("Authorization", util.GetBasicAuthHeader(webhook.User, webhook.Password)) } + if len(webhook.HttpHeader) != 0 { + for k, v := range webhook.HttpHeader { + request.Header.Set(k, v) + } + } + resp, err := ctxhttp.Do(ctx, http.DefaultClient, request) if err != nil { return err