diff --git a/manager/event.go b/manager/event.go index f0ef689a..8dc73e48 100644 --- a/manager/event.go +++ b/manager/event.go @@ -19,7 +19,7 @@ import ( "sort" ) -const eventNameLabel = "name" +const EventNameLabel = "alertname" type EventFingerprint uint64 @@ -28,16 +28,19 @@ type EventPayload map[string]string // Event models an action triggered by Prometheus. type Event struct { + // Short summary of event. + Summary string + // Long description of event. + Description string // Label value pairs for purpose of aggregation, matching, and disposition - // dispatching. This must minimally include a "name" label. + // dispatching. This must minimally include an "alertname" label. Labels EventLabels // Extra key/value information which is not used for aggregation. Payload EventPayload } func (e Event) Name() string { - // BUG: ensure in a proper place that all events have a name? - return e.Labels[eventNameLabel] + return e.Labels[EventNameLabel] } func (e Event) Fingerprint() EventFingerprint { diff --git a/web/api/event.go b/web/api/event.go index 509f085d..90fa9488 100644 --- a/web/api/event.go +++ b/web/api/event.go @@ -14,14 +14,31 @@ package api import ( + "log" "net/http" "github.com/prometheus/alert_manager/manager" ) func (s AlertManagerService) AddEvents(es manager.Events) { + for i, ev := range es { + if ev.Summary == "" || ev.Description == "" { + log.Printf("Missing field in event %d: %s", i, ev) + rb := s.ResponseBuilder() + rb.SetResponseCode(http.StatusBadRequest) + return + } + if _, ok := ev.Labels[manager.EventNameLabel]; !ok { + log.Printf("Missing alert name label in event %d: %s", i, ev) + rb := s.ResponseBuilder() + rb.SetResponseCode(http.StatusBadRequest) + return + } + } + err := s.Aggregator.Receive(es) if err != nil { + log.Println("Error during aggregation:", err) rb := s.ResponseBuilder() rb.SetResponseCode(http.StatusServiceUnavailable) } diff --git a/web/helpers.go b/web/helpers.go index ac5b6659..00631e9a 100644 --- a/web/helpers.go +++ b/web/helpers.go @@ -15,6 +15,7 @@ package web import ( "html/template" + "reflect" "time" ) @@ -22,6 +23,31 @@ func timeSince(t time.Time) string { return time.Now().Round(time.Second / 10).Sub(t.Round(time.Second / 10)).String() } +// By Russ Cox, https://groups.google.com/d/msg/golang-nuts/OEdSDgEC7js/iyhU9DW_IKcJ. +func eq(args ...interface{}) bool { + if len(args) == 0 { + return false + } + x := args[0] + switch x := x.(type) { + case string, int, int64, byte, float32, float64: + for _, y := range args[1:] { + if x == y { + return true + } + } + return false + } + + for _, y := range args[1:] { + if reflect.DeepEqual(x, y) { + return true + } + } + return false +} + var webHelpers = template.FuncMap{ "timeSince": timeSince, + "eq": eq, } diff --git a/web/templates/alerts.html b/web/templates/alerts.html index e85c66ce..9200b27c 100644 --- a/web/templates/alerts.html +++ b/web/templates/alerts.html @@ -27,14 +27,16 @@ <td> <span class="label label-important">{{index .Event.Name}}</span> <form class="add_silence_form"> - <input type="hidden" name="label[]" value="name"> - <input type="hidden" name="value[]" value="{{.Event.Labels.name}}"> + <input type="hidden" name="label[]" value="alertname"> + <input type="hidden" name="value[]" value="{{.Event.Name}}"> <a href="#edit_silence_modal" role="button" class="btn btn-mini add_silence_btn" data-toggle="modal">Silence Alert</a> </form> </td> <td> {{range $label, $value := .Event.Labels}} - <span class="label label-info"><b>{{$label}}</b>="{{$value}}"</span> + {{if not (eq $label "alertname")}} + <span class="label label-info"><b>{{$label}}</b>="{{$value}}"</span> + {{end}} {{end}} <form class="add_silence_form"> {{range $label, $value := .Event.Labels}}