2017-02-07 10:50:49 -06:00
package notifiers
import (
"encoding/json"
2017-02-08 04:24:49 -06:00
"strconv"
"strings"
"fmt"
2017-02-07 10:50:49 -06:00
"github.com/grafana/grafana/pkg/bus"
2019-05-13 01:45:54 -05:00
"github.com/grafana/grafana/pkg/infra/log"
2017-02-08 04:24:49 -06:00
"github.com/grafana/grafana/pkg/models"
2017-02-07 10:50:49 -06:00
"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 : `
< h3 class = "page-heading" > HipChat settings < / h3 >
< div class = "gf-form max-width-30" >
2017-02-08 04:24:49 -06:00
< span class = "gf-form-label width-8" > Hip Chat Url < / span >
< input type = "text" required class = "gf-form-input max-width-30" ng - model = "ctrl.model.settings.url" placeholder = "HipChat URL (ex https://grafana.hipchat.com)" > < / input >
2017-02-07 10:50:49 -06:00
< / div >
< div class = "gf-form max-width-30" >
2017-02-08 04:24:49 -06:00
< span class = "gf-form-label width-8" > API Key < / span >
2017-02-07 10:50:49 -06:00
< input type = "text" required class = "gf-form-input max-width-30" ng - model = "ctrl.model.settings.apikey" placeholder = "HipChat API Key" > < / input >
< / div >
< div class = "gf-form max-width-30" >
2017-02-08 04:24:49 -06:00
< span class = "gf-form-label width-8" > Room ID < / span >
2017-02-07 10:50:49 -06:00
< input type = "text"
class = "gf-form-input max-width-30"
ng - model = "ctrl.model.settings.roomid"
data - placement = "right" >
< / input >
< / div >
` ,
} )
}
2017-02-08 04:24:49 -06:00
const (
maxFieldCount int = 4
)
2019-05-20 08:23:06 -05:00
// NewHipChatNotifier is the constructor functions
// for the HipChatNotifier
2017-02-08 04:24:49 -06:00
func NewHipChatNotifier ( model * models . AlertNotification ) ( alerting . Notifier , error ) {
2017-02-07 10:50:49 -06:00
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 ( )
2019-05-20 08:23:06 -05:00
roomID := model . Settings . Get ( "roomid" ) . MustString ( )
2017-02-07 10:50:49 -06:00
return & HipChatNotifier {
2018-06-05 03:27:29 -05:00
NotifierBase : NewNotifierBase ( model ) ,
2019-05-20 08:23:06 -05:00
URL : url ,
APIKey : apikey ,
RoomID : roomID ,
2017-02-07 10:50:49 -06:00
log : log . New ( "alerting.notifier.hipchat" ) ,
} , nil
}
2019-05-20 08:23:06 -05:00
// HipChatNotifier is responsible for sending
// alert notifications to Hipchat.
2017-02-07 10:50:49 -06:00
type HipChatNotifier struct {
NotifierBase
2019-05-20 08:23:06 -05:00
URL string
APIKey string
RoomID string
2017-02-07 10:50:49 -06:00
log log . Logger
}
2019-05-20 08:23:06 -05:00
// Notify sends an alert notification to HipChat
func ( hc * HipChatNotifier ) Notify ( evalContext * alerting . EvalContext ) error {
2019-06-03 03:25:58 -05:00
hc . log . Info ( "Executing hipchat notification" , "ruleId" , evalContext . Rule . ID , "notification" , hc . Name )
2017-02-07 10:50:49 -06:00
2019-06-03 03:25:58 -05:00
ruleURL , err := evalContext . GetRuleURL ( )
2017-02-07 10:50:49 -06:00
if err != nil {
2019-05-20 08:23:06 -05:00
hc . log . Error ( "Failed get rule link" , "error" , err )
2017-02-07 10:50:49 -06:00
return err
}
2017-08-24 06:40:33 -05:00
attributes := make ( [ ] map [ string ] interface { } , 0 )
2017-02-07 10:50:49 -06:00
for index , evt := range evalContext . EvalMatches {
2017-10-04 09:07:13 -05:00
metricName := evt . Metric
if len ( metricName ) > 50 {
metricName = metricName [ : 50 ]
}
2017-08-24 06:40:33 -05:00
attributes = append ( attributes , map [ string ] interface { } {
2017-10-04 09:07:13 -05:00
"label" : metricName ,
2017-08-24 06:40:33 -05:00
"value" : map [ string ] interface { } {
"label" : strconv . FormatFloat ( evt . Value . Float64 , 'f' , - 1 , 64 ) ,
} ,
2017-02-07 10:50:49 -06:00
} )
2017-02-08 04:24:49 -06:00
if index > maxFieldCount {
2017-02-07 10:50:49 -06:00
break
}
}
if evalContext . Error != nil {
2017-08-24 06:40:33 -05:00
attributes = append ( attributes , map [ string ] interface { } {
"label" : "Error message" ,
"value" : map [ string ] interface { } {
"label" : evalContext . Error . Error ( ) ,
} ,
2017-02-07 10:50:49 -06:00
} )
}
2017-08-24 06:40:33 -05:00
message := ""
2018-04-13 11:40:14 -05:00
if evalContext . Rule . State != models . AlertStateOK { //don't add message when going back to alert state ok.
2017-02-07 10:50:49 -06:00
message += " " + evalContext . Rule . Message
}
2017-10-04 09:07:13 -05:00
2017-10-05 09:00:55 -05:00
if message == "" {
2017-10-04 09:07:13 -05:00
message = evalContext . GetNotificationTitle ( ) + " in state " + evalContext . GetStateModel ( ) . Text
}
2017-02-07 10:50:49 -06:00
//HipChat has a set list of colors
2017-02-08 04:24:49 -06:00
var color string
2017-02-07 10:50:49 -06:00
switch evalContext . Rule . State {
2017-02-08 04:24:49 -06:00
case models . AlertStateOK :
2017-02-07 10:50:49 -06:00
color = "green"
2017-02-08 04:24:49 -06:00
case models . AlertStateNoData :
2018-09-14 10:22:07 -05:00
color = "gray"
2017-02-08 04:24:49 -06:00
case models . AlertStateAlerting :
2017-02-07 10:50:49 -06:00
color = "red"
}
// Add a card with link to the dashboard
card := map [ string ] interface { } {
2017-08-24 06:40:33 -05:00
"style" : "application" ,
2019-05-20 08:23:06 -05:00
"url" : ruleURL ,
2017-02-07 10:50:49 -06:00
"id" : "1" ,
"title" : evalContext . GetNotificationTitle ( ) ,
2017-08-24 06:40:33 -05:00
"description" : message ,
2017-02-07 10:50:49 -06:00
"icon" : map [ string ] interface { } {
2017-03-21 09:37:55 -05:00
"url" : "https://grafana.com/assets/img/fav32.png" ,
2017-02-07 10:50:49 -06:00
} ,
2017-08-24 06:40:33 -05:00
"date" : evalContext . EndTime . Unix ( ) ,
"attributes" : attributes ,
2017-02-07 10:50:49 -06:00
}
2020-03-30 17:46:01 -05:00
if hc . NeedsImage ( ) && evalContext . ImagePublicURL != "" {
2017-08-24 07:52:23 -05:00
card [ "thumbnail" ] = map [ string ] interface { } {
2019-06-03 03:25:58 -05:00
"url" : evalContext . ImagePublicURL ,
"url@2x" : evalContext . ImagePublicURL ,
2017-08-24 07:52:23 -05:00
"width" : 1193 ,
"height" : 564 ,
}
}
2017-02-07 10:50:49 -06:00
body := map [ string ] interface { } {
"message" : message ,
"notify" : "true" ,
"message_format" : "html" ,
"color" : color ,
"card" : card ,
}
2017-02-08 04:24:49 -06:00
2019-05-20 08:23:06 -05:00
hipURL := fmt . Sprintf ( "%s/v2/room/%s/notification?auth_token=%s" , hc . URL , hc . RoomID , hc . APIKey )
2017-02-07 10:50:49 -06:00
data , _ := json . Marshal ( & body )
2019-05-20 08:23:06 -05:00
hc . log . Info ( "Request payload" , "json" , string ( data ) )
cmd := & models . SendWebhookSync { Url : hipURL , Body : string ( data ) }
2017-02-07 10:50:49 -06:00
if err := bus . DispatchCtx ( evalContext . Ctx , cmd ) ; err != nil {
2019-05-20 08:23:06 -05:00
hc . log . Error ( "Failed to send hipchat notification" , "error" , err , "webhook" , hc . Name )
2017-02-07 10:50:49 -06:00
return err
}
return nil
}