mirror of
https://github.com/prometheus/alertmanager
synced 2024-12-29 09:32:16 +00:00
Outlined slack notification support
This commit is contained in:
parent
c8e0343660
commit
e209c8b4fc
@ -27,6 +27,14 @@ var (
|
||||
DefaultSlackConfig = SlackConfig{
|
||||
ColorFiring: "warning",
|
||||
ColorResolved: "good",
|
||||
|
||||
Templates: SlackTemplates{
|
||||
Title: "slack_default_title",
|
||||
TitleLink: "slack_default_title_link",
|
||||
Pretext: "slack_default_pretext",
|
||||
Text: "slack_default_text",
|
||||
Fallback: "slack_default_fallback",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@ -151,8 +159,7 @@ func (c *HipchatConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
|
||||
// Configuration for notification via Slack.
|
||||
type SlackConfig struct {
|
||||
// Slack webhook URL, (https://api.slack.com/incoming-webhooks).
|
||||
WebhookURL string `yaml:"webhook_url"`
|
||||
URL string `yaml:"url"`
|
||||
|
||||
// Slack channel override, (like #other-channel or @username).
|
||||
Channel string `yaml:"channel"`
|
||||
@ -161,10 +168,20 @@ type SlackConfig struct {
|
||||
ColorFiring string `yaml:"color_firing"`
|
||||
ColorResolved string `yaml:"color_resolved"`
|
||||
|
||||
Templates SlackTemplates `yaml:"templates"`
|
||||
|
||||
// Catches all undefined fields and must be empty after parsing.
|
||||
XXX map[string]interface{} `yaml:",inline"`
|
||||
}
|
||||
|
||||
type SlackTemplates struct {
|
||||
Title string `yaml:"title"`
|
||||
TitleLink string `yaml:"title_link"`
|
||||
Pretext string `yaml:"pretext"`
|
||||
Text string `yaml:"text"`
|
||||
Fallback string `yaml:"fallback"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *SlackConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultSlackConfig
|
||||
@ -172,8 +189,8 @@ func (c *SlackConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
if err := unmarshal((*plain)(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.WebhookURL == "" {
|
||||
return fmt.Errorf("missing webhook URL in Slack config")
|
||||
if c.URL == "" {
|
||||
return fmt.Errorf("missing URL in Slack config")
|
||||
}
|
||||
if c.Channel == "" {
|
||||
return fmt.Errorf("missing channel in Slack config")
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"text/template"
|
||||
|
||||
"github.com/prometheus/common/log"
|
||||
"github.com/prometheus/common/model"
|
||||
@ -67,7 +68,6 @@ func (w *Webhook) Notify(ctx context.Context, alerts ...*types.Alert) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(fabxc): implement retrying as long as context is not canceled.
|
||||
resp, err := ctxhttp.Post(ctx, http.DefaultClient, w.URL, contentTypeJSON, &buf)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -80,3 +80,98 @@ func (w *Webhook) Notify(ctx context.Context, alerts ...*types.Alert) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Slack struct {
|
||||
conf *config.SlackConfig
|
||||
}
|
||||
|
||||
// slackReq is the request for sending a slack notification.
|
||||
type slackReq struct {
|
||||
Channel string `json:"channel,omitempty"`
|
||||
Attachments []slackAttachment `json:"attachments"`
|
||||
}
|
||||
|
||||
// slackAttachment is used to display a richly-formatted message block.
|
||||
type slackAttachment struct {
|
||||
Title string `json:"title,omitempty"`
|
||||
TitleLink string `json:"title_link,omitempty"`
|
||||
Pretext string `json:"pretext,omitempty"`
|
||||
Text string `json:"text"`
|
||||
Fallback string `json:"fallback"`
|
||||
|
||||
Color string `json:"color,omitempty"`
|
||||
MrkdwnIn []string `json:"mrkdwn_in,omitempty"`
|
||||
Fields []slackAttachmentField `json:"fields,omitempty"`
|
||||
}
|
||||
|
||||
// slackAttachmentField is displayed in a table inside the message attachment.
|
||||
type slackAttachmentField struct {
|
||||
Title string `json:"title"`
|
||||
Value string `json:"value"`
|
||||
Short bool `json:"short,omitempty"`
|
||||
}
|
||||
|
||||
func (n *Slack) Notify(ctx context.Context, as ...*types.Alert) error {
|
||||
var (
|
||||
alerts = types.Alerts(as...)
|
||||
color = n.conf.ColorResolved
|
||||
status = string(model.AlertResolved)
|
||||
)
|
||||
if alerts.HasFiring() {
|
||||
color = n.conf.ColorFiring
|
||||
status = string(model.AlertFiring)
|
||||
}
|
||||
|
||||
var title, link, pretext, text, fallback bytes.Buffer
|
||||
|
||||
if err := tmpl.ExecuteTemplate(&title, n.conf.Templates.Title, alerts); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tmpl.ExecuteTemplate(&text, n.conf.Templates.Text, alerts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attachment := &slackAttachment{
|
||||
Title: title.String(),
|
||||
TitleLink: link.String(),
|
||||
Pretext: pretext.String(),
|
||||
Text: text.String(),
|
||||
Fallback: fallback.String(),
|
||||
|
||||
Fields: []slackAttachmentField{{
|
||||
Title: "Status",
|
||||
Value: status,
|
||||
Short: true,
|
||||
}},
|
||||
Color: color,
|
||||
MrkdwnIn: []string{"fallback", "pretext"},
|
||||
}
|
||||
req := &slackReq{
|
||||
Channel: n.conf.Channel,
|
||||
Attachments: []slackAttachment{*attachment},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := ctxhttp.Post(ctx, http.DefaultClient, n.conf.URL, contentTypeJSON, &buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO(fabxc): is 2xx status code really indicator for success for Slack API?
|
||||
resp.Body.Close()
|
||||
|
||||
if resp.StatusCode/100 != 2 {
|
||||
return fmt.Errorf("unexpected status code %v", resp.StatusCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var tmpl *template.Template
|
||||
|
||||
func init() {
|
||||
tmpl = template.Must(template.ParseGlob("templates/*.tmpl"))
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ func (n *RetryNotifier) Notify(ctx context.Context, alerts ...*types.Alert) erro
|
||||
select {
|
||||
case <-tick.C:
|
||||
if err := n.Notifier.Notify(ctx, alerts...); err != nil {
|
||||
log.Warnf("notify attempt %d failed: %s", i, err)
|
||||
log.Warnf("Notify attempt %d failed: %s", i, err)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user