diff --git a/config/config.go b/config/config.go index 64bd3216..ea7a34e2 100644 --- a/config/config.go +++ b/config/config.go @@ -143,10 +143,10 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error { } for _, pdc := range nc.PagerdutyConfigs { if pdc.URL == "" { - if c.Global.PagerDutyURL == "" { + if c.Global.PagerdutyURL == "" { return fmt.Errorf("no global PagerDuty URL set") } - pdc.URL = c.Global.PagerDutyURL + pdc.URL = c.Global.PagerdutyURL } } names[nc.Name] = struct{}{} @@ -161,7 +161,7 @@ var DefaultGlobalConfig = GlobalConfig{ type GlobalConfig struct { Smarthost string `yaml:"smarthost"` SlackURL string `yaml:"slack_url"` - PagerDutyURL string `yaml:"pagerduty_url"` + PagerdutyURL string `yaml:"pagerduty_url"` } func (c *GlobalConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { diff --git a/config/notifies.go b/config/notifies.go index c12dc445..68e54c30 100644 --- a/config/notifies.go +++ b/config/notifies.go @@ -44,8 +44,8 @@ var ( }, } - DefaultPagerDutyConfig = PagerDutyConfig{ - Templates: PagerDutyTemplates{ + DefaultPagerdutyConfig = PagerdutyConfig{ + Templates: PagerdutyTemplates{ Description: "pagerduty.default.description", }, } @@ -56,19 +56,19 @@ type PagerdutyConfig struct { ServiceKey string `yaml:"service_key"` URL string `yaml:"url"` - Templates PagerDutyTemplates `yaml:"templates"` + Templates PagerdutyTemplates `yaml:"templates"` // Catches all undefined fields and must be empty after parsing. XXX map[string]interface{} `yaml:",inline"` } -type PagerDutyTemplates struct { +type PagerdutyTemplates struct { Description string } // UnmarshalYAML implements the yaml.Unmarshaler interface. func (c *PagerdutyConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { - *c = DefaultPagerDutyConfig + *c = DefaultPagerdutyConfig type plain PagerdutyConfig if err := unmarshal((*plain)(c)); err != nil { return err diff --git a/notify/impl.go b/notify/impl.go index fc1e5520..9dc7c434 100644 --- a/notify/impl.go +++ b/notify/impl.go @@ -51,6 +51,9 @@ func Build(confs []*config.NotificationConfig, tmpl *template.Template) map[stri for i, c := range nc.EmailConfigs { add(i, NewEmail(c, tmpl)) } + for i, c := range nc.PagerdutyConfigs { + add(i, NewPagerDuty(c, tmpl)) + } res[nc.Name] = fo } @@ -210,6 +213,68 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) error { return n.tmpl.ExecuteHTML(wc, n.conf.Templates.HTML, &data) } +type PagerDuty struct { + conf *config.PagerdutyConfig + tmpl *template.Template +} + +func NewPagerDuty(c *config.PagerdutyConfig, t *template.Template) *PagerDuty { + return &PagerDuty{conf: c, tmpl: t} +} + +const ( + pagerDutyEventTrigger = "trigger" + pagerDutyEventResolve = "resolve" +) + +type pagerDutyMessage struct { + ServiceKey string `json:"service_key"` + EventType string `json:"event_type"` + Description string `json:"description"` + IncidentKey uint64 `json:"incident_key"` + Client string `json:"client,omitempty"` + ClientURL string `json:"client_url,omitempty"` + Details map[string]string `json:"details"` +} + +func (pd *PagerDuty) Notify(ctx context.Context, as ...*types.Alert) error { + // http://developer.pagerduty.com/documentation/integration/events/trigger + alerts := types.Alerts(as...) + + eventType := pagerDutyEventTrigger + if alerts.Status() == model.AlertResolved { + eventType = pagerDutyEventResolve + } + + msg := &pagerDutyMessage{ + ServiceKey: pd.conf.ServiceKey, + EventType: eventType, + IncidentKey: 123, + Description: "", + Details: nil, + } + if eventType == pagerDutyEventTrigger { + msg.Client = "Prometheus Alertmanager" + msg.ClientURL = "" + } + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(msg); err != nil { + return err + } + + resp, err := ctxhttp.Post(ctx, http.DefaultClient, pd.conf.URL, contentTypeJSON, &buf) + if err != nil { + return err + } + resp.Body.Close() + + if resp.StatusCode/100 != 2 { + return fmt.Errorf("unexpected status code %v", resp.StatusCode) + } + return nil +} + type Slack struct { conf *config.SlackConfig tmpl *template.Template diff --git a/route.go b/route.go index ff0d377e..a573130d 100644 --- a/route.go +++ b/route.go @@ -97,12 +97,14 @@ func NewRoute(cr *config.Route, parent *RouteOpts) *Route { matchers = append(matchers, m) } - return &Route{ + route := &Route{ RouteOpts: opts, Matchers: matchers, Continue: cr.Continue, Routes: NewRoutes(cr.Routes, &opts), } + + return route } func NewRoutes(croutes []*config.Route, parent *RouteOpts) Routes { diff --git a/ui/app/partials/alerts.html b/ui/app/partials/alerts.html index f8c55d4e..c1e7c5a9 100644 --- a/ui/app/partials/alerts.html +++ b/ui/app/partials/alerts.html @@ -24,14 +24,20 @@
- - - - - - - -
{{ name }}{{ val }}
+
+ + + + + + + +
{{ name }}{{ val }}
+
+ +
+ +