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";
}
}