2017-07-04 08:16:32 -05:00
package notifiers
import (
2018-10-25 05:17:05 -05:00
"fmt"
2018-11-08 04:44:00 -06:00
"net/url"
2019-02-01 23:36:10 -06:00
"strings"
2018-10-25 05:17:05 -05:00
2017-07-04 08:16:32 -05:00
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
2019-05-13 01:45:54 -05:00
"github.com/grafana/grafana/pkg/infra/log"
2019-05-14 01:15:05 -05:00
"github.com/grafana/grafana/pkg/models"
2017-07-04 08:16:32 -05:00
"github.com/grafana/grafana/pkg/services/alerting"
)
2019-05-20 08:23:06 -05:00
const defaultDingdingMsgType = "link"
const dingdingOptionsTemplate = `
2017-07-04 08:16:32 -05:00
< h3 class = "page-heading" > DingDing settings < / h3 >
< div class = "gf-form" >
< span class = "gf-form-label width-10" > Url < / span >
2018-11-08 04:44:00 -06:00
< input type = "text" required class = "gf-form-input max-width-70" ng - model = "ctrl.model.settings.url" placeholder = "https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxx" > < / input >
2017-07-04 08:16:32 -05:00
< / div >
2018-10-25 05:29:47 -05:00
< div class = "gf-form" >
< span class = "gf-form-label width-10" > MessageType < / span >
2019-05-20 08:23:06 -05:00
< select class = "gf-form-input max-width-14" ng - model = "ctrl.model.settings.msgType" ng - options = "s for s in ['link','actionCard']" ng - init = "ctrl.model.settings.msgType=ctrl.model.settings.msgType || '` + defaultDingdingMsgType + `'" > < / select >
2018-10-25 05:29:47 -05:00
< / div >
2018-10-25 05:24:04 -05:00
`
func init ( ) {
alerting . RegisterNotifier ( & alerting . NotifierPlugin {
Type : "dingding" ,
Name : "DingDing" ,
Description : "Sends HTTP POST request to DingDing" ,
2019-05-20 08:23:06 -05:00
Factory : newDingDingNotifier ,
OptionsTemplate : dingdingOptionsTemplate ,
2017-07-04 08:16:32 -05:00
} )
}
2019-05-20 08:23:06 -05:00
func newDingDingNotifier ( model * models . AlertNotification ) ( alerting . Notifier , error ) {
2017-07-04 08:16:32 -05:00
url := model . Settings . Get ( "url" ) . MustString ( )
if url == "" {
return nil , alerting . ValidationError { Reason : "Could not find url property in settings" }
}
2019-05-20 08:23:06 -05:00
msgType := model . Settings . Get ( "msgType" ) . MustString ( defaultDingdingMsgType )
2018-10-25 05:29:47 -05:00
2017-07-04 08:16:32 -05:00
return & DingDingNotifier {
2019-02-01 23:35:17 -06:00
NotifierBase : NewNotifierBase ( model ) ,
MsgType : msgType ,
2019-05-20 08:23:06 -05:00
URL : url ,
2019-02-01 23:35:17 -06:00
log : log . New ( "alerting.notifier.dingding" ) ,
2017-07-04 08:16:32 -05:00
} , nil
}
2019-05-20 08:23:06 -05:00
// DingDingNotifier is responsible for sending alert notifications to ding ding.
2017-07-04 08:16:32 -05:00
type DingDingNotifier struct {
NotifierBase
2019-02-01 23:35:17 -06:00
MsgType string
2019-05-20 08:23:06 -05:00
URL string
2019-02-01 23:35:17 -06:00
log log . Logger
2017-07-04 08:16:32 -05:00
}
2019-05-20 08:23:06 -05:00
// Notify sends the alert notification to dingding.
func ( dd * DingDingNotifier ) Notify ( evalContext * alerting . EvalContext ) error {
dd . log . Info ( "Sending dingding" )
2017-07-04 08:16:32 -05:00
2019-06-03 03:25:58 -05:00
messageURL , err := evalContext . GetRuleURL ( )
2017-07-04 08:16:32 -05:00
if err != nil {
2019-05-20 08:23:06 -05:00
dd . log . Error ( "Failed to get messageUrl" , "error" , err , "dingding" , dd . Name )
messageURL = ""
2017-07-04 08:16:32 -05:00
}
2018-11-08 04:44:00 -06:00
2019-02-01 23:35:17 -06:00
q := url . Values {
"pc_slide" : { "false" } ,
2019-05-20 08:23:06 -05:00
"url" : { messageURL } ,
2018-11-08 04:44:00 -06:00
}
2019-02-01 23:35:17 -06:00
// Use special link to auto open the message url outside of Dingding
// Refer: https://open-doc.dingtalk.com/docs/doc.htm?treeId=385&articleId=104972&docType=1#s9
2019-05-20 08:23:06 -05:00
messageURL = "dingtalk://dingtalkclient/page/link?" + q . Encode ( )
2019-02-01 23:35:17 -06:00
2019-05-20 08:23:06 -05:00
dd . log . Info ( "messageUrl:" + messageURL )
2017-07-04 08:16:32 -05:00
message := evalContext . Rule . Message
2019-06-03 03:25:58 -05:00
picURL := evalContext . ImagePublicURL
2017-07-04 08:16:32 -05:00
title := evalContext . GetNotificationTitle ( )
2018-10-19 04:17:38 -05:00
if message == "" {
message = title
}
2017-07-04 08:16:32 -05:00
2018-10-25 05:17:05 -05:00
for i , match := range evalContext . EvalMatches {
2018-10-25 05:53:45 -05:00
message += fmt . Sprintf ( "\\n%2d. %s: %s" , i + 1 , match . Metric , match . Value )
2018-10-25 05:17:05 -05:00
}
2018-10-25 05:29:47 -05:00
var bodyStr string
2019-05-20 08:23:06 -05:00
if dd . MsgType == "actionCard" {
2018-11-11 21:18:53 -06:00
// Embed the pic into the markdown directly because actionCard doesn't have a picUrl field
2019-05-20 08:23:06 -05:00
if picURL != "" {
message = "![](" + picURL + ")\\n\\n" + message
2018-11-11 21:18:53 -06:00
}
2018-10-25 05:29:47 -05:00
bodyStr = ` {
"msgtype" : "actionCard" ,
"actionCard" : {
2019-02-01 23:36:10 -06:00
"text" : "` + strings.Replace(message, `" ` , "'", -1) + ` " ,
"title" : "` + strings.Replace(title, `" ` , "'", -1) + ` " ,
2018-10-25 05:29:47 -05:00
"singleTitle" : "More" ,
2019-05-20 08:23:06 -05:00
"singleURL" : "` + messageURL + `"
2018-10-25 05:29:47 -05:00
}
} `
} else {
bodyStr = ` {
"msgtype" : "link" ,
"link" : {
"text" : "` + message + `" ,
"title" : "` + title + `" ,
2019-05-20 08:23:06 -05:00
"picUrl" : "` + picURL + `" ,
"messageUrl" : "` + messageURL + `"
2018-10-25 05:29:47 -05:00
}
} `
}
2018-10-25 05:24:04 -05:00
bodyJSON , err := simplejson . NewJson ( [ ] byte ( bodyStr ) )
2017-07-04 08:16:32 -05:00
if err != nil {
2019-05-20 08:23:06 -05:00
dd . log . Error ( "Failed to create Json data" , "error" , err , "dingding" , dd . Name )
2017-07-04 08:16:32 -05:00
}
2018-04-10 15:22:12 -05:00
body , err := bodyJSON . MarshalJSON ( )
if err != nil {
return err
}
2017-07-04 08:16:32 -05:00
2019-05-14 01:15:05 -05:00
cmd := & models . SendWebhookSync {
2019-05-20 08:23:06 -05:00
Url : dd . URL ,
2017-07-04 08:16:32 -05:00
Body : string ( body ) ,
}
if err := bus . DispatchCtx ( evalContext . Ctx , cmd ) ; err != nil {
2019-05-20 08:23:06 -05:00
dd . log . Error ( "Failed to send DingDing" , "error" , err , "dingding" , dd . Name )
2017-07-04 08:16:32 -05:00
return err
}
return nil
}