Merge pull request #80 from t0mk/html_template

HTML template for notifications with FlowDock
This commit is contained in:
Julius Volz 2015-07-22 12:58:25 +02:00
commit 80743177b8
2 changed files with 102 additions and 4 deletions

View File

@ -20,6 +20,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"html" "html"
htmltemplate "html/template"
"io" "io"
"io/ioutil" "io/ioutil"
"net" "net"
@ -62,6 +63,23 @@ Payload labels:
{{range $label, $value := .Alert.Payload}} {{range $label, $value := .Alert.Payload}}
{{$label}} = "{{$value}}"{{end}}`)) {{$label}} = "{{$value}}"{{end}}`))
var contentTmpl = htmltemplate.Must(htmltemplate.New("content").Parse(
`<p><b><i>{{.Alert.Description}}</i></b></p>
<div><i>Grouping labels</i></div>
<ul>
{{range $label, $value := .Alert.Labels}}
<li><b>{{$label}}:</b> {{$value}}</li>
{{end}}
</ul>
<div><i>Payload labels</i></div>
<ul>
{{range $label, $value := .Alert.Payload}}
<li><b>{{$label}}:</b> {{$value}}</li>
{{end}}
</ul>`))
var ( var (
notificationBufferSize = flag.Int("notification.buffer-size", 1000, "Size of buffer for pending notifications.") notificationBufferSize = flag.Int("notification.buffer-size", 1000, "Size of buffer for pending notifications.")
pagerdutyAPIURL = flag.String("notification.pagerduty.url", "https://events.pagerduty.com/generic/2010-04-15/create_event.json", "PagerDuty API URL.") pagerdutyAPIURL = flag.String("notification.pagerduty.url", "https://events.pagerduty.com/generic/2010-04-15/create_event.json", "PagerDuty API URL.")
@ -356,7 +374,10 @@ type flowdockMessage struct {
} }
func (n *notifier) sendFlowdockNotification(op notificationOp, config *pb.FlowdockConfig, a *Alert) error { func (n *notifier) sendFlowdockNotification(op notificationOp, config *pb.FlowdockConfig, a *Alert) error {
flowdockMessage := newFlowdockMessage(op, config, a) flowdockMessage, err := newFlowdockMessage(op, config, a)
if err != nil {
return err
}
url := strings.TrimRight(*flowdockURL, "/") + "/" + config.GetApiToken() url := strings.TrimRight(*flowdockURL, "/") + "/" + config.GetApiToken()
jsonMessage, err := json.Marshal(flowdockMessage) jsonMessage, err := json.Marshal(flowdockMessage)
if err != nil { if err != nil {
@ -372,7 +393,7 @@ func (n *notifier) sendFlowdockNotification(op notificationOp, config *pb.Flowdo
return nil return nil
} }
func newFlowdockMessage(op notificationOp, config *pb.FlowdockConfig, a *Alert) *flowdockMessage { func newFlowdockMessage(op notificationOp, config *pb.FlowdockConfig, a *Alert) (*flowdockMessage, error) {
status := "" status := ""
switch op { switch op {
case notificationOpTrigger: case notificationOpTrigger:
@ -380,17 +401,22 @@ func newFlowdockMessage(op notificationOp, config *pb.FlowdockConfig, a *Alert)
case notificationOpResolve: case notificationOpResolve:
status = "resolved" status = "resolved"
} }
contentBuf := &bytes.Buffer{}
err := contentTmpl.Execute(contentBuf, struct{ Alert *Alert }{Alert: a})
if err != nil {
return nil, err
}
msg := &flowdockMessage{ msg := &flowdockMessage{
Source: "Prometheus", Source: "Prometheus",
FromAddress: config.GetFromAddress(), FromAddress: config.GetFromAddress(),
Subject: html.EscapeString(a.Summary), Subject: html.EscapeString(a.Summary),
Format: "html", Format: "html",
Content: fmt.Sprintf("*%s %s*: %s (<%s|view>)", html.EscapeString(a.Labels["alertname"]), status, html.EscapeString(a.Summary), a.Payload["generatorURL"]), Content: contentBuf.String(),
Link: a.Payload["generatorURL"], Link: a.Payload["generatorURL"],
Tags: append(config.GetTag(), status), Tags: append(config.GetTag(), status),
} }
return msg return msg, nil
} }
type webhookMessage struct { type webhookMessage struct {

View File

@ -18,6 +18,7 @@ import (
"crypto/tls" "crypto/tls"
"encoding/json" "encoding/json"
"fmt" "fmt"
"html"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@ -225,3 +226,74 @@ func TestSendWebhookNotification(t *testing.T) {
t.Errorf("incorrect webhook notification: Expected: %s Actual: %s", expected, msg) t.Errorf("incorrect webhook notification: Expected: %s Actual: %s", expected, msg)
} }
} }
func TestSendFlowdockNotification(t *testing.T) {
var body []byte
var url string
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var err error
url = r.URL.String()
body, err = ioutil.ReadAll(r.Body)
if err != nil {
t.Errorf("error reading flowdock notification: %s", err)
}
}))
defer ts.Close()
flowdockURL = &ts.URL
testApiToken := "123"
testFromAddress := "from@prometheus.io"
testTag := []string{"T1", "T2"}
config := &pb.FlowdockConfig{
ApiToken: &testApiToken,
FromAddress: &testFromAddress,
Tag: testTag,
}
alert := &Alert{
Summary: "Testsummary",
Description: "Test alert description, something went wrong here.",
Labels: AlertLabelSet{
"alertname": "TestAlert",
},
Payload: AlertPayload{
"payload_label1": "payload_value1",
"generatorURL": "http://graph",
},
}
n := &notifier{}
err := n.sendFlowdockNotification(notificationOpTrigger, config, alert)
if err != nil {
t.Errorf("error sending flowdock notification: %s", err)
}
var msg flowdockMessage
expectedUrl := "/" + testApiToken
if url != expectedUrl {
t.Error("Flowdock message POSTed to wrong URL, expected %s and got %s", expectedUrl, url)
}
err = json.Unmarshal(body, &msg)
if err != nil {
t.Errorf("error unmarshalling flowdock notification: %s", err)
}
contentBuf := &bytes.Buffer{}
err = contentTmpl.Execute(contentBuf, struct{ Alert *Alert }{Alert: alert})
if err != nil {
t.Errorf("error expanding expected HTML content for Flowdock message: %s", err)
}
expected := flowdockMessage{
Source: "Prometheus",
FromAddress: testFromAddress,
Subject: html.EscapeString(alert.Summary),
Format: "html",
Content: contentBuf.String(),
Link: "http://graph",
Tags: append(testTag, "firing"),
}
if !reflect.DeepEqual(msg, expected) {
t.Errorf("incorrect Flowdock notification: Expected: %s Actual: %s", expected, msg)
}
}