1
2
3
4
5
6
7
8
9
10
11
12
13
14 package pushover
15
16 import (
17 "context"
18 "fmt"
19 "net/http"
20 "net/url"
21 "strings"
22 "time"
23
24 "github.com/go-kit/log"
25 "github.com/go-kit/log/level"
26 commoncfg "github.com/prometheus/common/config"
27
28 "github.com/prometheus/alertmanager/config"
29 "github.com/prometheus/alertmanager/notify"
30 "github.com/prometheus/alertmanager/template"
31 "github.com/prometheus/alertmanager/types"
32 )
33
34 const (
35
36 maxTitleLenRunes = 250
37
38 maxMessageLenRunes = 1024
39
40 maxURLLenRunes = 512
41 )
42
43
44 type Notifier struct {
45 conf *config.PushoverConfig
46 tmpl *template.Template
47 logger log.Logger
48 client *http.Client
49 retrier *notify.Retrier
50 apiURL string
51 }
52
53
54 func New(c *config.PushoverConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {
55 client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "pushover", httpOpts...)
56 if err != nil {
57 return nil, err
58 }
59 return &Notifier{
60 conf: c,
61 tmpl: t,
62 logger: l,
63 client: client,
64 retrier: ¬ify.Retrier{},
65 apiURL: "https://api.pushover.net/1/messages.json",
66 }, nil
67 }
68
69
70 func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) {
71 key, ok := notify.GroupKey(ctx)
72 if !ok {
73 return false, fmt.Errorf("group key missing")
74 }
75 data := notify.GetTemplateData(ctx, n.tmpl, as, n.logger)
76
77 level.Debug(n.logger).Log("incident", key)
78
79 var (
80 err error
81 message string
82 )
83 tmpl := notify.TmplText(n.tmpl, data, &err)
84 tmplHTML := notify.TmplHTML(n.tmpl, data, &err)
85
86 parameters := url.Values{}
87 parameters.Add("token", tmpl(string(n.conf.Token)))
88 parameters.Add("user", tmpl(string(n.conf.UserKey)))
89
90 title, truncated := notify.TruncateInRunes(tmpl(n.conf.Title), maxTitleLenRunes)
91 if truncated {
92 level.Warn(n.logger).Log("msg", "Truncated title", "incident", key, "max_runes", maxTitleLenRunes)
93 }
94 parameters.Add("title", title)
95
96 if n.conf.HTML {
97 parameters.Add("html", "1")
98 message = tmplHTML(n.conf.Message)
99 } else {
100 message = tmpl(n.conf.Message)
101 }
102
103 message, truncated = notify.TruncateInRunes(message, maxMessageLenRunes)
104 if truncated {
105 level.Warn(n.logger).Log("msg", "Truncated message", "incident", key, "max_runes", maxMessageLenRunes)
106 }
107 message = strings.TrimSpace(message)
108 if message == "" {
109
110 message = "(no details)"
111 }
112 parameters.Add("message", message)
113
114 supplementaryURL, truncated := notify.TruncateInRunes(tmpl(n.conf.URL), maxURLLenRunes)
115 if truncated {
116 level.Warn(n.logger).Log("msg", "Truncated URL", "incident", key, "max_runes", maxURLLenRunes)
117 }
118 parameters.Add("url", supplementaryURL)
119 parameters.Add("url_title", tmpl(n.conf.URLTitle))
120
121 parameters.Add("priority", tmpl(n.conf.Priority))
122 parameters.Add("retry", fmt.Sprintf("%d", int64(time.Duration(n.conf.Retry).Seconds())))
123 parameters.Add("expire", fmt.Sprintf("%d", int64(time.Duration(n.conf.Expire).Seconds())))
124 parameters.Add("sound", tmpl(n.conf.Sound))
125 if err != nil {
126 return false, err
127 }
128
129 u, err := url.Parse(n.apiURL)
130 if err != nil {
131 return false, err
132 }
133 u.RawQuery = parameters.Encode()
134
135 level.Debug(n.logger).Log("msg", "Sending message", "incident", key)
136 resp, err := notify.PostText(ctx, n.client, u.String(), nil)
137 if err != nil {
138 return true, notify.RedactURL(err)
139 }
140 defer notify.Drain(resp)
141
142 return n.retrier.Check(resp.StatusCode, resp.Body)
143 }
144
View as plain text