From 13b106bb2b76f1c6397eee4db8b5a13ab1f25edf Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Mon, 22 Jul 2013 11:05:49 +0200 Subject: [PATCH 1/5] Ensure flag parsing on startup. --- main.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main.go b/main.go index 10d847897b..abd0e6a18e 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,7 @@ package main import ( + "flag" "log" "github.com/prometheus/alert_manager/manager" @@ -22,6 +23,8 @@ import ( ) func main() { + flag.Parse() + log.Print("Starting event suppressor...") suppressor := manager.NewSuppressor() defer suppressor.Close() From 436643f94e9d3d277baf0d462f0e806879d9b9d5 Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Mon, 22 Jul 2013 11:07:26 +0200 Subject: [PATCH 2/5] Cleanup: rename "element" to "event". --- manager/aggregator.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/manager/aggregator.go b/manager/aggregator.go index f158cb0152..c7b965c948 100644 --- a/manager/aggregator.go +++ b/manager/aggregator.go @@ -172,11 +172,11 @@ func (a *Aggregator) aggregate(req *aggregateEventsRequest, s SummaryReceiver) { return } log.Println("aggregating", *req) - for _, element := range req.Events { + for _, event := range req.Events { for _, r := range a.Rules { - log.Println("Checking rule", r, r.Handles(element)) - if r.Handles(element) { - fp := element.Fingerprint() + log.Println("Checking rule", r, r.Handles(event)) + if r.Handles(event) { + fp := event.Fingerprint() aggregation, ok := a.Aggregates[fp] if !ok { expTimer := time.AfterFunc(minimumRefreshPeriod, func() { @@ -192,7 +192,7 @@ func (a *Aggregator) aggregate(req *aggregateEventsRequest, s SummaryReceiver) { a.Aggregates[fp] = aggregation } - aggregation.Ingest(element) + aggregation.Ingest(event) aggregation.SendNotification(s) break } From 71a9d4af35bd2cef64cc4740aab0753fbe0a620f Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Mon, 22 Jul 2013 11:07:53 +0200 Subject: [PATCH 3/5] Ensure minimum repeat rate for events. --- manager/aggregator.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/manager/aggregator.go b/manager/aggregator.go index c7b965c948..139dee8bfd 100644 --- a/manager/aggregator.go +++ b/manager/aggregator.go @@ -20,6 +20,7 @@ import ( ) const ( + minimumRepeatRate = 5 * time.Minute minimumRefreshPeriod = 5 * time.Minute notificationRetryPeriod = 1 * time.Minute ) @@ -213,6 +214,13 @@ type aggregatorResetRulesRequest struct { func (a *Aggregator) replaceRules(r *aggregatorResetRulesRequest) { log.Println("Replacing", len(r.Rules), "aggregator rules...") + + for _, rule := range r.Rules { + if rule.RepeatRate < minimumRepeatRate { + log.Println("Rule repeat rate too low, setting to minimum value") + rule.RepeatRate = minimumRepeatRate + } + } a.Rules = r.Rules r.Response <- new(aggregatorResetRulesResponse) From 827d3c37105dfb9a4c6e895885165ba00480f6a0 Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Mon, 22 Jul 2013 11:11:18 +0200 Subject: [PATCH 4/5] Show actual alerts in UI and add no-op silence dialog. --- web/helpers.go | 27 ++++++++++++++++++++ web/static/css/default.css | 12 +++++++++ web/static/js/alerts.js | 49 ++++++++++++++++++++++++++++++++++++ web/templates/_base.html | 44 +++++++++++++++++++++++++++++++- web/templates/alerts.html | 50 ++++++++++++++++++------------------- web/templates/silences.html | 3 ++- web/web.go | 11 +++++--- 7 files changed, 164 insertions(+), 32 deletions(-) create mode 100644 web/helpers.go create mode 100644 web/static/js/alerts.js diff --git a/web/helpers.go b/web/helpers.go new file mode 100644 index 0000000000..ac5b6659ab --- /dev/null +++ b/web/helpers.go @@ -0,0 +1,27 @@ +// Copyright 2013 Prometheus Team +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package web + +import ( + "html/template" + "time" +) + +func timeSince(t time.Time) string { + return time.Now().Round(time.Second / 10).Sub(t.Round(time.Second / 10)).String() +} + +var webHelpers = template.FuncMap{ + "timeSince": timeSince, +} diff --git a/web/static/css/default.css b/web/static/css/default.css index 3af5ad33d2..2eb08a8a72 100644 --- a/web/static/css/default.css +++ b/web/static/css/default.css @@ -1,3 +1,15 @@ body { padding-top: 60px; } + +#create_silence_modal th { + text-align: left; +} + +.add_silence_form { + display: inline; +} + +.del_label_button { + margin-bottom: 10px; +} diff --git a/web/static/js/alerts.js b/web/static/js/alerts.js new file mode 100644 index 0000000000..a821362d4f --- /dev/null +++ b/web/static/js/alerts.js @@ -0,0 +1,49 @@ +function clearSilenceLabels() { + $("#silence_label_table").empty(); +} + +function addSilenceLabel(label, value) { + if (!label) { + label = ""; + } + if (!value) { + value = ""; + } + $("#silence_label_table").append( + '' + + ' ' + + ' ' + + ' ' + + ''); + bindDelLabel(); +} + +function bindDelLabel() { + $(".del_label_button").unbind("click"); + $(".del_label_button").click(function() { + $(this).parents("tr").remove(); + }); +} + +function init() { + $("#new_silence_btn").click(function() { + clearSilenceLabels(); + }); + + $(".add_silence_btn").click(function() { + clearSilenceLabels(); + + var form = $(this).parents("form"); + var labels = form.children('input[name="label[]"]'); + var values = form.children('input[name="value[]"]'); + for (var i = 0; i < labels.length; i++) { + addSilenceLabel(labels.get(i).value, values.get(i).value); + } + }); + + $("#add_label_button").click(function() { + addSilenceLabel("", ""); + }); +} + +$(init); diff --git a/web/templates/_base.html b/web/templates/_base.html index 60af04553a..79970b81b8 100644 --- a/web/templates/_base.html +++ b/web/templates/_base.html @@ -5,8 +5,10 @@ Prometheus Alert Manager + + - + @@ -43,3 +45,43 @@ +{{define "createSilenceModal"}} + + +{{end}} diff --git a/web/templates/alerts.html b/web/templates/alerts.html index be9bcd2052..6cf43a4f27 100644 --- a/web/templates/alerts.html +++ b/web/templates/alerts.html @@ -8,7 +8,7 @@

Alerts

- +
@@ -23,34 +23,32 @@

Alerts

{{range .AlertAggregates}} - - - - + + + + {{end}} - - - - - - - - - - - - - - - - - - - - -
{{.Event}} {{.Event.Labels}} {{.Created}}{{.LastRefreshed}} + {{index .Event.Name}} +
+ + + Silence Alert +
+
+ {{range $label, $value := .Event.Labels}} + {{$label}}="{{$value}}", + {{end}} +
+ {{range $label, $value := .Event.Labels}} + + + {{end}} + Silence Instance +
+
{{timeSince .Created}} ago{{timeSince .LastRefreshed}} ago No
TheTaxesAreTooDamnHigh {foo="bar",baz="biz"} ......No
TheTaxesAreTooDamnHigh {foo="bar",baz="biz"} ......No
TheTaxesAreTooDamnHigh {foo="bar",baz="biz"} ......No
+ {{template "createSilenceModal" .}} {{end}} diff --git a/web/templates/silences.html b/web/templates/silences.html index 1476e5d878..5e3d2c988d 100644 --- a/web/templates/silences.html +++ b/web/templates/silences.html @@ -6,7 +6,7 @@ {{define "content"}}

Silences

-

+

New Silence

@@ -90,4 +90,5 @@

Silences

+ {{template "createSilenceModal" .}} {{end}} diff --git a/web/web.go b/web/web.go index 4f035c0214..f2f919de9f 100644 --- a/web/web.go +++ b/web/web.go @@ -76,14 +76,17 @@ func (w WebService) ServeForever() error { } func getLocalTemplate(name string) (*template.Template, error) { - return template.ParseFiles( + t := template.New("_base.html") + t.Funcs(webHelpers) + return t.ParseFiles( "web/templates/_base.html", fmt.Sprintf("web/templates/%s.html", name), ) } func getEmbeddedTemplate(name string) (*template.Template, error) { - t := template.New("_base") + t := template.New("_base.html") + t.Funcs(webHelpers) file, err := blob.GetFile(blob.TemplateFiles, "_base.html") if err != nil { @@ -110,10 +113,10 @@ func getTemplate(name string) (t *template.Template, err error) { } if err != nil { - return + return nil, err } - return + return t, nil } func executeTemplate(w http.ResponseWriter, name string, data interface{}) { From ed289d58f0d48e5d683bee535e078171dc197c3e Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Mon, 22 Jul 2013 16:26:54 +0200 Subject: [PATCH 5/5] Remove crufty logging statement. --- manager/aggregator.go | 1 - 1 file changed, 1 deletion(-) diff --git a/manager/aggregator.go b/manager/aggregator.go index 139dee8bfd..22dab706ad 100644 --- a/manager/aggregator.go +++ b/manager/aggregator.go @@ -175,7 +175,6 @@ func (a *Aggregator) aggregate(req *aggregateEventsRequest, s SummaryReceiver) { log.Println("aggregating", *req) for _, event := range req.Events { for _, r := range a.Rules { - log.Println("Checking rule", r, r.Handles(event)) if r.Handles(event) { fp := event.Fingerprint() aggregation, ok := a.Aggregates[fp]