diff --git a/pkg/services/alerting/notifiers/hipchat.go b/pkg/services/alerting/notifiers/hipchat.go new file mode 100644 index 00000000000..ad649cb084d --- /dev/null +++ b/pkg/services/alerting/notifiers/hipchat.go @@ -0,0 +1,155 @@ +package notifiers + +import ( + "encoding/json" + "strconv" + "strings" + + "fmt" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/alerting" +) + +func init() { + alerting.RegisterNotifier(&alerting.NotifierPlugin{ + Type: "hipchat", + Name: "HipChat", + Description: "Sends notifications uto a HipChat Room", + Factory: NewHipChatNotifier, + OptionsTemplate: ` +

HipChat settings

+
+ Hip Chat Url + +
+
+ API Key + +
+
+ Room ID + + +
+ `, + }) + +} + +const ( + maxFieldCount int = 4 +) + +func NewHipChatNotifier(model *models.AlertNotification) (alerting.Notifier, error) { + url := model.Settings.Get("url").MustString() + if strings.HasSuffix(url, "/") { + url = url[:len(url)-1] + } + if url == "" { + return nil, alerting.ValidationError{Reason: "Could not find url property in settings"} + } + + apikey := model.Settings.Get("apikey").MustString() + roomId := model.Settings.Get("roomid").MustString() + + return &HipChatNotifier{ + NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings), + Url: url, + ApiKey: apikey, + RoomId: roomId, + log: log.New("alerting.notifier.hipchat"), + }, nil +} + +type HipChatNotifier struct { + NotifierBase + Url string + ApiKey string + RoomId string + log log.Logger +} + +func (this *HipChatNotifier) Notify(evalContext *alerting.EvalContext) error { + this.log.Info("Executing hipchat notification", "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 + } + + message := evalContext.GetNotificationTitle() + " in state " + evalContext.GetStateModel().Text + "
Check Dasboard" + fields := make([]map[string]interface{}, 0) + message += "
" + for index, evt := range evalContext.EvalMatches { + message += evt.Metric + " :: " + strconv.FormatFloat(evt.Value.Float64, 'f', -1, 64) + "
" + fields = append(fields, map[string]interface{}{ + "title": evt.Metric, + "value": evt.Value, + "short": true, + }) + if index > maxFieldCount { + break + } + } + + if evalContext.Error != nil { + fields = append(fields, map[string]interface{}{ + "title": "Error message", + "value": evalContext.Error.Error(), + "short": false, + }) + } + + if evalContext.Rule.State != models.AlertStateOK { //dont add message when going back to alert state ok. + message += " " + evalContext.Rule.Message + } + //HipChat has a set list of colors + var color string + switch evalContext.Rule.State { + case models.AlertStateOK: + color = "green" + case models.AlertStateNoData: + color = "grey" + case models.AlertStateAlerting: + color = "red" + } + + // Add a card with link to the dashboard + card := map[string]interface{}{ + "style": "link", + "url": ruleUrl, + "id": "1", + "title": evalContext.GetNotificationTitle(), + "description": evalContext.GetNotificationTitle() + " in state " + evalContext.GetStateModel().Text, + "icon": map[string]interface{}{ + "url": "http://grafana.org/assets/img/fav32.png", + }, + "date": evalContext.EndTime.Unix(), + } + + body := map[string]interface{}{ + "message": message, + "notify": "true", + "message_format": "html", + "color": color, + "card": card, + } + + hipUrl := fmt.Sprintf("%s/v2/room/%s/notification?auth_token=%s", this.Url, this.RoomId, this.ApiKey) + data, _ := json.Marshal(&body) + cmd := &models.SendWebhookSync{Url: hipUrl, Body: string(data)} + + if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil { + this.log.Error("Failed to send hipchat notification", "error", err, "webhook", this.Name) + return err + } + + return nil +} diff --git a/pkg/services/alerting/notifiers/hipchat_test.go b/pkg/services/alerting/notifiers/hipchat_test.go new file mode 100644 index 00000000000..1597be12eb8 --- /dev/null +++ b/pkg/services/alerting/notifiers/hipchat_test.go @@ -0,0 +1,81 @@ +package notifiers + +import ( + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestHipChatNotifier(t *testing.T) { + Convey("HipChat 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: "hipchat", + Settings: settingsJSON, + } + + _, err := NewHipChatNotifier(model) + So(err, ShouldNotBeNil) + }) + + Convey("from settings", func() { + json := ` + { + "url": "http://google.com" + }` + + settingsJSON, _ := simplejson.NewJson([]byte(json)) + model := &m.AlertNotification{ + Name: "ops", + Type: "hipchat", + Settings: settingsJSON, + } + + not, err := NewHipChatNotifier(model) + hipchatNotifier := not.(*HipChatNotifier) + + So(err, ShouldBeNil) + So(hipchatNotifier.Name, ShouldEqual, "ops") + So(hipchatNotifier.Type, ShouldEqual, "hipchat") + So(hipchatNotifier.Url, ShouldEqual, "http://google.com") + So(hipchatNotifier.ApiKey, ShouldEqual, "") + So(hipchatNotifier.RoomId, ShouldEqual, "") + }) + + Convey("from settings with Recipient and Mention", func() { + json := ` + { + "url": "http://www.hipchat.com", + "apikey": "1234", + "roomid": "1234" + }` + + settingsJSON, _ := simplejson.NewJson([]byte(json)) + model := &m.AlertNotification{ + Name: "ops", + Type: "hipchat", + Settings: settingsJSON, + } + + not, err := NewHipChatNotifier(model) + hipchatNotifier := not.(*HipChatNotifier) + + So(err, ShouldBeNil) + So(hipchatNotifier.Name, ShouldEqual, "ops") + So(hipchatNotifier.Type, ShouldEqual, "hipchat") + So(hipchatNotifier.Url, ShouldEqual, "http://www.hipchat.com") + So(hipchatNotifier.ApiKey, ShouldEqual, "1234") + So(hipchatNotifier.RoomId, ShouldEqual, "1234") + }) + + }) + }) +} diff --git a/public/app/features/alerting/alert_tab_ctrl.ts b/public/app/features/alerting/alert_tab_ctrl.ts index 89b1c63372f..6be36380144 100644 --- a/public/app/features/alerting/alert_tab_ctrl.ts +++ b/public/app/features/alerting/alert_tab_ctrl.ts @@ -104,6 +104,7 @@ export class AlertTabCtrl { case "webhook": return "fa fa-cubes"; case "pagerduty": return "fa fa-bullhorn"; case "opsgenie": return "fa fa-bell"; + case "hipchat": return "fa fa-mail-forward"; } }