Add simple support for HipChat notifications

This commit is contained in:
Cameron Davison 2015-04-10 12:12:24 -05:00
parent 438e8b98b8
commit f4f6ceccc4
7 changed files with 155 additions and 7 deletions

3
.gitignore vendored
View File

@ -1,2 +1,5 @@
.deps/
alertmanager
*-stamp
*.config
silences.json

View File

@ -10,7 +10,8 @@ following aspects:
* aggregating alerts by labelset
* handling notification repeats
* sending alert notifications via external services (currently email,
[PagerDuty](http://www.pagerduty.com/) or
[PagerDuty](http://www.pagerduty.com/),
[HipChat](http://www.hipchat.com/), or
[Pushover](https://www.pushover.net/))
See [config/fixtures/sample.conf.input](config/fixtures/sample.conf.input) for

View File

@ -64,6 +64,14 @@ func (c Config) Validate() error {
return fmt.Errorf("Missing user key in Pushover notification config: %s", proto.MarshalTextString(ec))
}
}
for _, hcc := range nc.HipchatConfig {
if hcc.AuthToken == nil {
return fmt.Errorf("Missing token in HipChat config: %s", proto.MarshalTextString(hcc))
}
if hcc.RoomId == nil {
return fmt.Errorf("Missing room in HipChat config: %s", proto.MarshalTextString(hcc))
}
}
if _, ok := ncNames[nc.GetName()]; ok {
return fmt.Errorf("Notification config name not unique: %s", nc.GetName())

View File

@ -34,6 +34,20 @@ message PushoverConfig {
optional string user_key = 2;
}
// Configuration for notification via HipChat.
message HipChatConfig {
// https://www.hipchat.com/docs/apiv2/method/send_room_notification
// HipChat auth token, (https://www.hipchat.com/docs/api/auth).
optional string auth_token = 1;
// HipChat room id, (https://www.hipchat.com/rooms/ids).
optional int32 room_id = 2;
// Color of message.
optional string color = 3 [default = "purple"];
// Should this message notify or not.
optional bool notify = 4 [default = false];
}
// Notification configuration definition.
message NotificationConfig {
// Name of this NotificationConfig. Referenced from AggregationRule.
@ -44,6 +58,8 @@ message NotificationConfig {
repeated EmailConfig email_config = 3;
// Zero or more pushover notification configurations.
repeated PushoverConfig pushover_config = 4;
// Zero or more hipchat notification configurations.
repeated HipChatConfig hipchat_config = 5;
}
// A regex-based label filter used in aggregations.

View File

@ -10,6 +10,10 @@ notification_config {
token: "mypushovertoken"
user_key: "mypushoverkey"
}
hipchat_config {
auth_token: "hipchatauthtoken"
room_id: 123456
}
}
aggregation_rule {

View File

@ -2,15 +2,30 @@
// source: config.proto
// DO NOT EDIT!
/*
Package io_prometheus_alertmanager is a generated protocol buffer package.
It is generated from these files:
config.proto
It has these top-level messages:
PagerDutyConfig
EmailConfig
PushoverConfig
HipChatConfig
NotificationConfig
Filter
AggregationRule
InhibitRule
AlertManagerConfig
*/
package io_prometheus_alertmanager
import proto "code.google.com/p/goprotobuf/proto"
import json "encoding/json"
import proto "github.com/golang/protobuf/proto"
import math "math"
// Reference proto, json, and math imports to suppress error if they are not otherwise used.
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = &json.SyntaxError{}
var _ = math.Inf
// Configuration for notification via PagerDuty.
@ -77,6 +92,53 @@ func (m *PushoverConfig) GetUserKey() string {
return ""
}
type HipChatConfig struct {
// Hipchat auth token, https://www.hipchat.com/docs/api/auth
AuthToken *string `protobuf:"bytes,1,opt,name=auth_token" json:"auth_token,omitempty"`
// Hipchat room id, https://www.hipchat.com/rooms/ids
RoomId *int32 `protobuf:"varint,2,opt,name=room_id" json:"room_id,omitempty"`
// color of message
Color *string `protobuf:"bytes,3,opt,name=color,def=purple" json:"color,omitempty"`
// should this message notify or not
Notify *bool `protobuf:"varint,4,opt,name=notify,def=0" json:"notify,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *HipChatConfig) Reset() { *m = HipChatConfig{} }
func (m *HipChatConfig) String() string { return proto.CompactTextString(m) }
func (*HipChatConfig) ProtoMessage() {}
const Default_HipChatConfig_Color string = "purple"
const Default_HipChatConfig_Notify bool = false
func (m *HipChatConfig) GetAuthToken() string {
if m != nil && m.AuthToken != nil {
return *m.AuthToken
}
return ""
}
func (m *HipChatConfig) GetRoomId() int32 {
if m != nil && m.RoomId != nil {
return *m.RoomId
}
return 0
}
func (m *HipChatConfig) GetColor() string {
if m != nil && m.Color != nil {
return *m.Color
}
return Default_HipChatConfig_Color
}
func (m *HipChatConfig) GetNotify() bool {
if m != nil && m.Notify != nil {
return *m.Notify
}
return Default_HipChatConfig_Notify
}
// Notification configuration definition.
type NotificationConfig struct {
// Name of this NotificationConfig. Referenced from AggregationRule.
@ -87,6 +149,8 @@ type NotificationConfig struct {
EmailConfig []*EmailConfig `protobuf:"bytes,3,rep,name=email_config" json:"email_config,omitempty"`
// Zero or more pushover notification configurations.
PushoverConfig []*PushoverConfig `protobuf:"bytes,4,rep,name=pushover_config" json:"pushover_config,omitempty"`
// Zero or more hipchat notification configuration.
HipchatConfig []*HipChatConfig `protobuf:"bytes,5,rep,name=hipchat_config" json:"hipchat_config,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
@ -122,6 +186,13 @@ func (m *NotificationConfig) GetPushoverConfig() []*PushoverConfig {
return nil
}
func (m *NotificationConfig) GetHipchatConfig() []*HipChatConfig {
if m != nil {
return m.HipchatConfig
}
return nil
}
// A regex-based label filter used in aggregations.
type Filter struct {
// The regex matching the label name.

View File

@ -19,6 +19,7 @@ import (
"encoding/json"
"flag"
"fmt"
"html"
"io"
"io/ioutil"
"net"
@ -28,6 +29,7 @@ import (
"strings"
"sync"
"text/template"
"time"
"github.com/golang/glog"
"github.com/thorduri/pushover"
@ -56,6 +58,7 @@ var (
pagerdutyApiUrl = flag.String("pagerdutyApiUrl", "https://events.pagerduty.com/generic/2010-04-15/create_event.json", "PagerDuty API URL.")
smtpSmartHost = flag.String("smtpSmartHost", "", "Address of the smarthost to send all email notifications to.")
smtpSender = flag.String("smtpSender", "alertmanager@example.org", "Sender email address to use in email notifications.")
hipchatUrl = flag.String("hipchat.url", "https://api.hipchat.com/v2/", "HipChat API V2 URL.")
)
// A Notifier is responsible for sending notifications for alerts according to
@ -164,6 +167,43 @@ func (n *notifier) sendPagerDutyNotification(serviceKey string, a *Alert) error
return nil
}
func (n *notifier) sendHipChatNotification(authToken string, roomId int32, color string, notify bool, a *Alert) error {
// https://www.hipchat.com/docs/apiv2/method/send_room_notification
incidentKey := a.Fingerprint()
buf, err := json.Marshal(map[string]interface{}{
"color": color,
"message": fmt.Sprintf("%s: %s <a href='%s'>view</a>", html.EscapeString(a.Labels["alertname"]), html.EscapeString(a.Summary), a.Payload["GeneratorURL"]),
"notify": notify,
"message_format": "html",
})
if err != nil {
return err
}
timeout := time.Duration(5 * time.Second)
client := http.Client{
Timeout: timeout,
}
resp, err := client.Post(
*hipchatUrl+fmt.Sprintf("/room/%d/notification?auth_token=%s", roomId, authToken),
contentTypeJson,
bytes.NewBuffer(buf),
)
if err != nil {
return err
}
defer resp.Body.Close()
respBuf, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
glog.Infof("Sent HipChat notification: %v: HTTP %d: %s", incidentKey, resp.StatusCode, respBuf)
// BUG: Check response for result of operation.
return nil
}
func writeEmailBody(w io.Writer, from string, to string, a *Alert) error {
err := bodyTmpl.Execute(w, struct {
From string
@ -296,6 +336,11 @@ func (n *notifier) handleNotification(a *Alert, config *pb.NotificationConfig) {
glog.Error("Error sending Pushover notification: ", err)
}
}
for _, hcConfig := range config.HipchatConfig {
if err := n.sendHipChatNotification(hcConfig.GetAuthToken(), hcConfig.GetRoomId(), hcConfig.GetColor(), hcConfig.GetNotify(), a); err != nil {
glog.Error("Error sending HipChat notification: ", err)
}
}
}
func (n *notifier) Dispatch() {