Using Go’s templating language
You write notification templates in Go’s templating language, text/template.
Before you start creating your own notification templates, we recommend that you read through this topic, which provides you with an overview of Go’s templating language and writing templates in text/template.
Dot
In text/template there is a special cursor called dot, and is written as .
. You can think of this cursor as a variable whose value changes depending where in the template it is used. For example, at the start of a notification template .
refers to something called ExtendedData
which contains a number of fields including Alerts
, Status
, GroupLabels
, CommonLabels
, CommonAnnotations
and ExternalURL
. However, dot might refer to something else when used in a range over a list, when used inside a with
, or when writing feature templates to be used in other templates. You can see examples of this in Create notification templates, and all data and functions in the Reference.
Opening and closing tags
In text/template, templates start with {{
and end with }}
irrespective of whether the template prints a variable or executes control structures such as if statements. This is different from other templating languages such as Jinja where printing a variable uses {{
and }}
and control structures use {%
and %}
.
To print the value of something use {{
and }}
. You can print the value of dot, a field of dot, the result of a function, and the value of a variable. For example, to print the Alerts
field where dot refers to ExtendedData
you would write the following:
{{ .Alerts }}
Iterate over alerts
To print just the labels of each alert, rather than all information about the alert, you can use a range
to iterate the alerts in ExtendedData
:
{{ range .Alerts }}
{{ .Labels }}
{{ end }}
Inside the range dot no longer refers to ExtendedData
, but to an Alert
. You can use {{ .Labels }}
to print the labels of each alert. This works because {{ range .Alerts }}
changes dot to refer to the current alert in the list of alerts. When the range is finished dot is reset to the value it had before the start of the range, which in this example is ExtendedData
:
{{ range .Alerts }}
{{ .Labels }}
{{ end }}
{{/* does not work, .Labels does not exist here */}}
{{ .Labels }}
{{/* works, cursor was reset */}}
{{ .Status }}
Iterate over annotations and labels
Let’s write a template to print the labels of each alert in the format The name of the label is $name, and the value is $value
, where $name
and $value
contain the name and value of each label.
Like in the previous example, use a range to iterate over the alerts in .Alerts
such that dot refers to the current alert in the list of alerts, and then use a second range on the sorted labels so dot is updated a second time to refer to the current label. Inside the second range use .Name
and .Value
to print the name and value of each label:
{{ range .Alerts }}
{{ range .Labels.SortedPairs }}
The name of the label is {{ .Name }}, and the value is {{ .Value }}
{{ end }}
{{ range .Annotations.SortedPairs }}
The name of the annotation is {{ .Name }}, and the value is {{ .Value }}
{{ end }}
{{ end }}
The index function
To print a specific annotation or label use the index
function.
{{ range .Alerts }}
The name of the alert is {{ index .Labels "alertname" }}
{{ end }}
If statements
You can use if statements in templates. For example, to print There are no alerts
if there are no alerts in .Alerts
you would write the following:
{{ if .Alerts }}
There are alerts
{{ else }}
There are no alerts
{{ end }}
With
With is similar to if statements, however unlike if statements, with
updates dot to refer to the value of the with:
{{ with .Alerts }}
There are {{ len . }} alert(s)
{{ else }}
There are no alerts
{{ end }}
Variables
Variables in text/template must be created within the template. For example, to create a variable called $variable
with the current value of dot you would write the following:
{{ $variable := . }}
You can use $variable
inside a range or with
and it will refer to the value of dot at the time the variable was defined, not the current value of dot.
For example, you cannot write a template that use {{ .Labels }}
in the second range because here dot refers to the current label, not the current alert:
{{ range .Alerts }}
{{ range .Labels.SortedPairs }}
{{ .Name }} = {{ .Value }}
{{/* does not work because in the second range . is a label not an alert */}}
There are {{ len .Labels }}
{{ end }}
{{ end }}
You can fix this by defining a variable called $alert
in the first range and before the second range:
{{ range .Alerts }}
{{ $alert := . }}
{{ range .Labels.SortedPairs }}
{{ .Name }} = {{ .Value }}
{{/* works because $alert refers to the value of dot inside the first range */}}
There are {{ len $alert.Labels }}
{{ end }}
{{ end }}
Range with index
You can get the index of each alert within a range by defining index and value variables at the start of the range:
{{ $num_alerts := len .Alerts }}
{{ range $index, $alert := .Alerts }}
This is alert {{ $index }} out of {{ $num_alerts }}
{{ end }}
Define templates
You can define templates using define
and the name of the template in double quotes. You should not define templates with the same name as other templates, including default templates such as __subject
, __text_values_list
, __text_alert_list
, default.title
and default.message
. Where a template has been created with the same name as a default template, or a template in another notification template, Grafana might use either template. Grafana does not prevent, or show an error message, when there are two or more templates with the same name.
{{ define "print_labels" }}
{{ end }}
Execute templates
You can execute defined templates using template
, the name of the template in double quotes, and the cursor that should be passed to the template:
{{ template "print_labels" . }}
Pass data to templates
Within a template dot refers to the value that is passed to the template.
For example, if a template is passed a list of firing alerts then dot refers to that list of firing alerts:
{{ template "print_alerts" .Alerts }}
If the template is passed the sorted labels for an alert then dot refers to the list of sorted labels:
{{ template "print_labels" .SortedLabels }}
This is useful when writing reusable templates. For example, to print all alerts you might write the following:
{{ template "print_alerts" .Alerts }}
Then to print just the firing alerts you could write this:
{{ template "print_alerts" .Alerts.Firing }}
This works because both .Alerts
and .Alerts.Firing
is a list of alerts.
{{ define "print_alerts" }}
{{ range . }}
{{ template "print_labels" .SortedLabels }}
{{ end }}
{{ end }}
Comments
You can add comments with {{/*
and */}}
:
{{/* This is a comment */}}
To prevent comments from adding line breaks use:
{{- /* This is a comment with no leading or trailing line breaks */ -}}
Indentation
You can use indentation, both tabs and spaces, and line breaks, to make templates more readable:
{{ range .Alerts }}
{{ range .Labels.SortedPairs }}
{{ .Name }} = {{ .Value }}
{{ end }}
{{ end }}
However, indentation in the template is also present in the text. Next, we look at how to remove it.
Remove spaces and line breaks
In text/template use {{-
and -}}
to remove leading and trailing spaces and line breaks.
For example, when using indentation and line breaks to make a template more readable:
{{ range .Alerts }}
{{ range .Labels.SortedPairs }}
{{ .Name }} = {{ .Value }}
{{ end }}
{{ end }}
The indentation and line breaks will also be present in the text:
alertname = "Test"
grafana_folder = "Test alerts"
You can remove the indentation and line breaks from the text changing }}
to -}}
at the start of each range:
{{ range .Alerts -}}
{{ range .Labels.SortedPairs -}}
{{ .Name }} = {{ .Value }}
{{ end }}
{{ end }}
The indentation and line breaks in the template are now absent from the text:
alertname = "Test"
grafana_folder = "Test alerts"