From 8250ced75fce017bbe52463edf076ae6329aa7a9 Mon Sep 17 00:00:00 2001 From: Nick Satterly Date: Wed, 13 Apr 2016 22:26:10 +0100 Subject: [PATCH 1/2] Make Alerta event property configurable --- CHANGELOG.md | 1 + alert.go | 16 +++++++++++++++- integrations/streamer_test.go | 14 +++++++++----- pipeline/alert.go | 7 +++++++ 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33d84e4b6..0547ac640 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ For example, let's say we want to store all data that triggered an alert in Infl - [#426](https://github.com/influxdata/kapacitor/issues/426): Add `skip-format` query parameter to the `GET /task` endpoint so that returned TICKscript content is left unmodified from the user input. - [#388](https://github.com/influxdata/kapacitor/issues/388): The duration of an alert is now tracked and exposed as part of the alert data as well as can be set as a field via `.durationField('duration')`. - [#486](https://github.com/influxdata/kapacitor/pull/486): Default config file location. +- [#461](https://github.com/influxdata/kapacitor/pull/461): Make Alerta `event` property configurable. ### Bugfixes diff --git a/alert.go b/alert.go index 4cf828245..218dbad2f 100644 --- a/alert.go +++ b/alert.go @@ -232,6 +232,10 @@ func newAlertNode(et *ExecutingTask, n *pipeline.AlertNode, l *log.Logger) (an * if err != nil { return nil, err } + evtmpl, err := text.New("event").Parse(alerta.Event) + if err != nil { + return nil, err + } etmpl, err := text.New("environment").Parse(alerta.Environment) if err != nil { return nil, err @@ -247,6 +251,7 @@ func newAlertNode(et *ExecutingTask, n *pipeline.AlertNode, l *log.Logger) (an * ai := alertaHandler{ AlertaHandler: alerta, resourceTmpl: rtmpl, + eventTmpl: evtmpl, environmentTmpl: etmpl, groupTmpl: gtmpl, valueTmpl: vtmpl, @@ -873,6 +878,7 @@ type alertaHandler struct { *pipeline.AlertaHandler resourceTmpl *text.Template + eventTmpl *text.Template environmentTmpl *text.Template valueTmpl *text.Template groupTmpl *text.Template @@ -907,6 +913,14 @@ func (a *AlertNode) handleAlerta(alerta alertaHandler, ad *AlertData) { resource := buf.String() buf.Reset() + err = alerta.eventTmpl.Execute(&buf, ad.info) + if err != nil { + a.logger.Printf("E! failed to evaluate Alerta Event template %s", alerta.Event) + return + } + event := buf.String() + buf.Reset() + err = alerta.environmentTmpl.Execute(&buf, ad.info) if err != nil { a.logger.Printf("E! failed to evaluate Alerta Environment template %s", alerta.Environment) @@ -938,7 +952,7 @@ func (a *AlertNode) handleAlerta(alerta alertaHandler, ad *AlertData) { err = a.et.tm.AlertaService.Alert( alerta.Token, resource, - ad.ID, + event, environment, severity, group, diff --git a/integrations/streamer_test.go b/integrations/streamer_test.go index 7777d6311..f14e60ca3 100644 --- a/integrations/streamer_test.go +++ b/integrations/streamer_test.go @@ -2707,6 +2707,9 @@ func TestStream_AlertAlerta(t *testing.T) { if exp := "cpu"; pd.Resource != exp { t.Errorf("unexpected resource got %s exp %s", pd.Resource, exp) } + if exp := "serverA"; pd.Event != exp { + t.Errorf("unexpected event got %s exp %s", pd.Event, exp) + } if exp := "production"; pd.Environment != exp { t.Errorf("unexpected environment got %s exp %s", pd.Environment, exp) } @@ -2726,9 +2729,12 @@ func TestStream_AlertAlerta(t *testing.T) { if exp := "/alert?api-key=anothertesttoken"; r.URL.String() != exp { t.Errorf("unexpected url got %s exp %s", r.URL.String(), exp) } - if exp := "resource: cpu"; pd.Resource != exp { + if exp := "resource: serverA"; pd.Resource != exp { t.Errorf("unexpected resource got %s exp %s", pd.Resource, exp) } + if exp := "event: TestStream_Alert"; pd.Event != exp { + t.Errorf("unexpected event got %s exp %s", pd.Event, exp) + } if exp := "serverA"; pd.Environment != exp { t.Errorf("unexpected environment got %s exp %s", pd.Environment, exp) } @@ -2745,9 +2751,6 @@ func TestStream_AlertAlerta(t *testing.T) { t.Errorf("unexpected origin got %s exp %s", pd.Origin, exp) } } - if exp := "serverA"; pd.Event != exp { - t.Errorf("unexpected event got %s exp %s", pd.Event, exp) - } if exp := "kapacitor/cpu/serverA is CRITICAL @1971-01-01 00:00:10 +0000 UTC"; pd.Text != exp { t.Errorf("unexpected text got %s exp %s", pd.Text, exp) } @@ -2775,7 +2778,8 @@ stream .environment('production') .alerta() .token('anothertesttoken') - .resource('resource: {{ .Name }}') + .resource('resource: {{ index .Tags "host" }}') + .event('event: {{ .TaskName }}') .environment('{{ index .Tags "host" }}') .origin('override') .group('{{ .ID }}') diff --git a/pipeline/alert.go b/pipeline/alert.go index 8e2c9cf72..9d832d26d 100644 --- a/pipeline/alert.go +++ b/pipeline/alert.go @@ -751,6 +751,7 @@ func (a *AlertNode) Alerta() *AlertaHandler { alerta := &AlertaHandler{ AlertNode: a, Resource: defaultAlertaResource, + Event: defaultAlertaEvent, Group: defaultAlertaGroup, } a.AlertaHandlers = append(a.AlertaHandlers, alerta) @@ -758,6 +759,7 @@ func (a *AlertNode) Alerta() *AlertaHandler { } const defaultAlertaResource = "{{ .Name }}" +const defaultAlertaEvent = "{{ .ID }}" const defaultAlertaGroup = "{{ .Group }}" // tick:embedded:AlertNode.Alerta @@ -773,6 +775,11 @@ type AlertaHandler struct { // Default: {{ .Name }} Resource string + // Alerta event. + // Can be a template and has access to the same data as the AlertNode.Details property. + // Default: {{ .ID }} + Event string + // Alerta environment. // Can be a template and has access to the same data as the AlertNode.Details property. // Defaut is set from the configuration. From d5111de04d119f9686a21f6e0f230eb045f501c5 Mon Sep 17 00:00:00 2001 From: Nick Satterly Date: Sat, 23 Apr 2016 08:11:49 +0100 Subject: [PATCH 2/2] Provide only the idInfo struct when executing the event template This is so that the user cannot create an event with data that changes depending on the state of the alert. --- alert.go | 10 +++++++++- pipeline/alert.go | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/alert.go b/alert.go index 218dbad2f..4650e748c 100644 --- a/alert.go +++ b/alert.go @@ -913,7 +913,15 @@ func (a *AlertNode) handleAlerta(alerta alertaHandler, ad *AlertData) { resource := buf.String() buf.Reset() - err = alerta.eventTmpl.Execute(&buf, ad.info) + type eventData struct { + idInfo + ID string + } + data := eventData{ + idInfo: ad.info.messageInfo.idInfo, + ID: ad.ID, + } + err = alerta.eventTmpl.Execute(&buf, data) if err != nil { a.logger.Printf("E! failed to evaluate Alerta Event template %s", alerta.Event) return diff --git a/pipeline/alert.go b/pipeline/alert.go index 9d832d26d..489d2091a 100644 --- a/pipeline/alert.go +++ b/pipeline/alert.go @@ -776,7 +776,7 @@ type AlertaHandler struct { Resource string // Alerta event. - // Can be a template and has access to the same data as the AlertNode.Details property. + // Can be a template and has access to the same data as the idInfo property. // Default: {{ .ID }} Event string