From f1b2273d1352a9e4964fd1245c53eb0767370615 Mon Sep 17 00:00:00 2001 From: Roman Khavronenko Date: Tue, 16 Aug 2022 08:08:27 +0200 Subject: [PATCH] vmalert: support `$alertID` and `$groupID` in template variables (#2983) Support of these two variables allows building custom URLs with alert's ID and group ID params. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/517#issuecomment-1207141432 Signed-off-by: hagen1778 --- app/vmalert/README.md | 24 ++++++++++++++++++++---- app/vmalert/main.go | 3 ++- app/vmalert/notifier/alert.go | 12 ++++++++---- app/vmalert/notifier/alert_test.go | 13 +++++++++++++ docs/vmalert.md | 24 ++++++++++++++++++++---- 5 files changed, 63 insertions(+), 13 deletions(-) diff --git a/app/vmalert/README.md b/app/vmalert/README.md index 1ab2cc5a3..af514c28f 100644 --- a/app/vmalert/README.md +++ b/app/vmalert/README.md @@ -193,9 +193,25 @@ annotations: [ : ] ``` -It is allowed to use [Go templating](https://golang.org/pkg/text/template/) in annotations to format data, iterate over it or execute expressions. +#### Templating + +It is allowed to use [Go templating](https://golang.org/pkg/text/template/) in annotations to format data, iterate over +or execute expressions. +The following variables are available in templating: + +| Variable | Description | Example | +|------------------------------------|-----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------| +| $value or .Value | The current alert's value. Avoid using value in labels, it may cause unexpected issues. | "Number of connections is {{ $value }} | +| $labels or .Labels | The list of labels of the current alert. Use as ".Labels.". | "Too high number of connections for {{ .Labels.instance }}" | +| $alertID or .AlertID | The current alert's ID generated by vmalert. | "Link: vmalert/alert?group_id={{.GroupID}}&alert_id={{.AlertID}}" | +| $groupID or .GroupID | The current alert's group ID generated by vmalert. | "Link: vmalert/alert?group_id={{.GroupID}}&alert_id={{.AlertID}}" | +| $expr or .Expr | Alert's expression. Can be used for generating links to Grafana or other systems. | "/api/v1/query?query={{ $expr|quotesEscape|queryEscape }}" | +| $externalLabels or .ExternalLabels | List of labels configured via `-external.label` command-line flag. | "Issues with {{ $labels.instance }} (datacenter-{{ $externalLabels.dc }})" | +| $externalURL or .ExternalURL | URL configured via `-external.url` command-line flag. Used for cases when vmalert is hidden behind proxy. | "Visit {{ $externalURL }} for more details" | + Additionally, `vmalert` provides some extra templating functions -listed [here](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/app/vmalert/notifier/template_func.go) and [reusable templates](#reusable-templates). +listed [here](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/app/vmalert/notifier/template_func.go) +and [reusable templates](#reusable-templates). #### Reusable templates @@ -695,8 +711,8 @@ The shortlist of configuration flags is the following: -evaluationInterval duration How often to evaluate the rules (default 1m0s) -external.alert.source string - External Alert Source allows to override the Source link for alerts sent to AlertManager for cases where you want to build a custom link to Grafana, Prometheus or any other service. - eg. 'explore?orgId=1&left=[\"now-1h\",\"now\",\"VictoriaMetrics\",{\"expr\": \"{{$expr|quotesEscape|crlfEscape|queryEscape}}\"},{\"mode\":\"Metrics\"},{\"ui\":[true,true,true,\"none\"]}]'.If empty '/vmalert/api/v1/alert?group_id=&alert_id=' is used + External Alert Source allows to override the Source link for alerts sent to AlertManager for cases where you want to build a custom link to Grafana, Prometheus or any other service. + Supports templating. For example, link to Grafana: 'explore?orgId=1&left=[\"now-1h\",\"now\",\"VictoriaMetrics\",{\"expr\": \"{{$expr|quotesEscape|crlfEscape|queryEscape}}\"},{\"mode\":\"Metrics\"},{\"ui\":[true,true,true,\"none\"]}]'. (default "{{.ExternalURL}}/vmalert/api/v1/alert?group_id={{.GroupID}}&alert_id={{.AlertID}}") -external.label array Optional label in the form 'Name=value' to add to all generated recording rules and alerts. Pass multiple -label flags in order to add multiple label sets. Supports an array of values separated by comma or specified via multiple flags. diff --git a/app/vmalert/main.go b/app/vmalert/main.go index fa1ba773d..e37f1eec6 100644 --- a/app/vmalert/main.go +++ b/app/vmalert/main.go @@ -60,7 +60,8 @@ absolute path to all .tpl files in root.`) externalURL = flag.String("external.url", "", "External URL is used as alert's source for sent alerts to the notifier") externalAlertSource = flag.String("external.alert.source", "", `External Alert Source allows to override the Source link for alerts sent to AlertManager for cases where you want to build a custom link to Grafana, Prometheus or any other service. -eg. 'explore?orgId=1&left=[\"now-1h\",\"now\",\"VictoriaMetrics\",{\"expr\": \"{{$expr|quotesEscape|crlfEscape|queryEscape}}\"},{\"mode\":\"Metrics\"},{\"ui\":[true,true,true,\"none\"]}]'.If empty '/vmalert/api/v1/alert?group_id=&alert_id=' is used`) +Supports templating. For example, link to Grafana: 'explore?orgId=1&left=[\"now-1h\",\"now\",\"VictoriaMetrics\",{\"expr\": \"{{$expr|quotesEscape|crlfEscape|queryEscape}}\"},{\"mode\":\"Metrics\"},{\"ui\":[true,true,true,\"none\"]}]'. +If empty 'vmalert/api/v1/alert?group_id={{.GroupID}}&alert_id={{.AlertID}}' is used.`) externalLabels = flagutil.NewArray("external.label", "Optional label in the form 'Name=value' to add to all generated recording rules and alerts. "+ "Pass multiple -label flags in order to add multiple label sets.") diff --git a/app/vmalert/notifier/alert.go b/app/vmalert/notifier/alert.go index 4d88a1a82..88fc59544 100644 --- a/app/vmalert/notifier/alert.go +++ b/app/vmalert/notifier/alert.go @@ -74,9 +74,11 @@ func (as AlertState) String() string { // AlertTplData is used to execute templating type AlertTplData struct { - Labels map[string]string - Value float64 - Expr string + Labels map[string]string + Value float64 + Expr string + AlertID uint64 + GroupID uint64 } var tplHeaders = []string{ @@ -85,6 +87,8 @@ var tplHeaders = []string{ "{{ $expr := .Expr }}", "{{ $externalLabels := .ExternalLabels }}", "{{ $externalURL := .ExternalURL }}", + "{{ $alertID := .AlertID }}", + "{{ $groupID := .GroupID }}", } // ExecTemplate executes the Alert template for given @@ -92,7 +96,7 @@ var tplHeaders = []string{ // Every alert could have a different datasource, so function // requires a queryFunction as an argument. func (a *Alert) ExecTemplate(q templates.QueryFn, labels, annotations map[string]string) (map[string]string, error) { - tplData := AlertTplData{Value: a.Value, Labels: labels, Expr: a.Expr} + tplData := AlertTplData{Value: a.Value, Labels: labels, Expr: a.Expr, AlertID: a.ID, GroupID: a.GroupID} tmpl, err := templates.GetWithFuncs(templates.FuncsWithQuery(q)) if err != nil { return nil, fmt.Errorf("error getting a template: %w", err) diff --git a/app/vmalert/notifier/alert_test.go b/app/vmalert/notifier/alert_test.go index 1a55b99f7..47a4a11bb 100644 --- a/app/vmalert/notifier/alert_test.go +++ b/app/vmalert/notifier/alert_test.go @@ -109,6 +109,19 @@ func TestAlert_ExecTemplate(t *testing.T) { "description": fmt.Sprintf("It is 10000 connections for localhost (cluster-%s)", extCluster), }, }, + { + name: "alert and group IDs", + alert: &Alert{ + ID: 42, + GroupID: 24, + }, + annotations: map[string]string{ + "url": "/api/v1/alert?alertID={{$alertID}}&groupID={{$groupID}}", + }, + expTpl: map[string]string{ + "url": "/api/v1/alert?alertID=42&groupID=24", + }, + }, } qFn := func(q string) ([]datasource.Metric, error) { diff --git a/docs/vmalert.md b/docs/vmalert.md index e8a366731..7de7504ac 100644 --- a/docs/vmalert.md +++ b/docs/vmalert.md @@ -197,9 +197,25 @@ annotations: [ : ] ``` -It is allowed to use [Go templating](https://golang.org/pkg/text/template/) in annotations to format data, iterate over it or execute expressions. +#### Templating + +It is allowed to use [Go templating](https://golang.org/pkg/text/template/) in annotations to format data, iterate over +or execute expressions. +The following variables are available in templating: + +| Variable | Description | Example | +|------------------------------------|-----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------| +| $value or .Value | The current alert's value. Avoid using value in labels, it may cause unexpected issues. | "Number of connections is {{ $value }} | +| $labels or .Labels | The list of labels of the current alert. Use as ".Labels.". | "Too high number of connections for {{ .Labels.instance }}" | +| $alertID or .AlertID | The current alert's ID generated by vmalert. | "Link: vmalert/alert?group_id={{.GroupID}}&alert_id={{.AlertID}}" | +| $groupID or .GroupID | The current alert's group ID generated by vmalert. | "Link: vmalert/alert?group_id={{.GroupID}}&alert_id={{.AlertID}}" | +| $expr or .Expr | Alert's expression. Can be used for generating links to Grafana or other systems. | "/api/v1/query?query={{ $expr|quotesEscape|queryEscape }}" | +| $externalLabels or .ExternalLabels | List of labels configured via `-external.label` command-line flag. | "Issues with {{ $labels.instance }} (datacenter-{{ $externalLabels.dc }})" | +| $externalURL or .ExternalURL | URL configured via `-external.url` command-line flag. Used for cases when vmalert is hidden behind proxy. | "Visit {{ $externalURL }} for more details" | + Additionally, `vmalert` provides some extra templating functions -listed [here](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/app/vmalert/notifier/template_func.go) and [reusable templates](#reusable-templates). +listed [here](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/app/vmalert/notifier/template_func.go) +and [reusable templates](#reusable-templates). #### Reusable templates @@ -699,8 +715,8 @@ The shortlist of configuration flags is the following: -evaluationInterval duration How often to evaluate the rules (default 1m0s) -external.alert.source string - External Alert Source allows to override the Source link for alerts sent to AlertManager for cases where you want to build a custom link to Grafana, Prometheus or any other service. - eg. 'explore?orgId=1&left=[\"now-1h\",\"now\",\"VictoriaMetrics\",{\"expr\": \"{{$expr|quotesEscape|crlfEscape|queryEscape}}\"},{\"mode\":\"Metrics\"},{\"ui\":[true,true,true,\"none\"]}]'.If empty '/vmalert/api/v1/alert?group_id=&alert_id=' is used + External Alert Source allows to override the Source link for alerts sent to AlertManager for cases where you want to build a custom link to Grafana, Prometheus or any other service. + Supports templating. For example, link to Grafana: 'explore?orgId=1&left=[\"now-1h\",\"now\",\"VictoriaMetrics\",{\"expr\": \"{{$expr|quotesEscape|crlfEscape|queryEscape}}\"},{\"mode\":\"Metrics\"},{\"ui\":[true,true,true,\"none\"]}]'. (default "{{.ExternalURL}}/vmalert/api/v1/alert?group_id={{.GroupID}}&alert_id={{.AlertID}}") -external.label array Optional label in the form 'Name=value' to add to all generated recording rules and alerts. Pass multiple -label flags in order to add multiple label sets. Supports an array of values separated by comma or specified via multiple flags.