

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用 Go 的模板语言
<a name="v9-alerting-notifications-go-templating"></a>

****  
本文档主题专为支持 **Grafana 9.x 版本**的 Grafana 工作区而设计。  
对于支持 Grafana 10.x 版本的 Grafana 工作区，请参阅[使用 Grafana 版本 10](using-grafana-v10.md)。  
对于支持 Grafana 8.x 版本的 Grafana 工作区，请参阅[使用 Grafana 版本 8](using-grafana-v8.md)。

您可以使用 Go 的模板语言 [text/template](https://pkg.go.dev/text/template) 编写通知模板。

本节概述了 Go 的模板语言以及如何用 text/template 编写模板。

## dot
<a name="v9-go-dot"></a>

里面 text/template 有一个叫做 dot 的特殊光标，写成`.`了。您可以将此光标看作一个变量，其值会根据在模板中使用的位置而变化。例如，在通知模板 `.` 的开头引用 `ExtendedData` 对象，该对象包含多个字段，例如包括 `Alerts`、`Status`、`GroupLabels`、`CommonLabels`、`CommonAnnotations` 和 `ExternalURL`。但是，当在列表上的 `range` 中使用、在 `with` 中使用或编写要在其他模板中使用的功能模板时，dot 可能引用其他内容。您可以在 [创建通知模板](v9-alerting-create-templates.md) 中看到相关示例，在 [模板参考](v9-alerting-template-reference.md) 中看到所有数据和函数。

## 开始和结束标签
<a name="v9-go-openclosetags"></a>

在 text/template 中，模板以 `{{` 开头，以 `}}` 结尾，无论模板是打印变量还是运行 if 语句等控制结构。这与 Jinja 等其他模板语言不同，在 Jinja 中，打印变量使用 `{{` 和 `}}`，控制结构使用 `{%` 和 `%}`。

## Print（打印）
<a name="v9-go-print"></a>

要打印某项的值，请使用 `{{` 和 `}}`。您可以打印 dot 的值、dot 的字段、函数的结果和[变量](#v9-go-variables)的值。例如，要打印 `Alerts` 字段，其中 dot 引用 `ExtendedData`，您可以编写以下内容：

```
{{ .Alerts }}
```

## 迭代警报
<a name="v9-go-iterate-alerts"></a>

要仅打印每个警报的标签，而不是有关警报的所有信息，可使用 `range` 在 `ExtendedData` 中迭代警报：

```
{{ range .Alerts }}
{{ .Labels }}
{{ end }}
```

范围内的 dot 不再引用 `ExtendedData`，而是引用 `Alert`。您可以使用 `{{ .Labels }}` 打印每个警报的标签。之所以有效，是因为 `{{ range .Alerts }}` 会更改 dot，以引用警报列表中的当前警报。范围完成后，dot 将重置为范围开始之前的值，在本例中为 `ExtendedData`：

```
{{ range .Alerts }}
{{ .Labels }}
{{ end }}
{{/* does not work, .Labels does not exist here */}}
{{ .Labels }}
{{/* works, cursor was reset */}}
{{ .Status }}
```

## 迭代注释和标签
<a name="v9-go-iterate-labels"></a>

我们编写一个模板，以 `The name of the label is $name, and the value is $value` 格式打印每个警报的标签，其中 `$name` 和 `$value` 包含每个标签的名称和值。

与前面的示例一样，使用一个范围迭代 `.Alerts` 中的警报，使 dot 引用警报列表中的当前警报，然后在排序标签上使用第二个范围，使 dot 第二次更新以引用当前标签。在第二个范围内，使用 `.Name` 和 `.Value` 打印每个标签的名称和值：

```
{{ 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 }}
```

## If 语句
<a name="v9-go-if"></a>

可在模板中使用 if 语句。例如，要在 `.Alerts` 中没有警报的情况下打印 `There are no alerts`，您可以编写以下内容：

```
{{ if .Alerts }}
There are alerts
{{ else }}
There are no alerts
{{ end }}
```

## With
<a name="v9-go-with"></a>

With 与 if 语句类似，但又有所不同，`with` 会更新 dot 以引用 with 的值：

```
{{ with .Alerts }}
There are {{ len . }} alert(s)
{{ else }}
There are no alerts
{{ end }}
```

## 变量
<a name="v9-go-variables"></a>

中的变量 text/template 必须在模板中创建。例如，要使用 dot 的当前值创建一个名为 `$variable` 的变量，您可以编写以下内容：

```
{{ $variable := . }}
```

您可以在范围或 `with` 内使用 `$variable`，以引用定义变量时的 dot 值，而不是当前 dot 的值。

例如，您不能编写在第二个范围中使用 `{{ .Labels }}` 的模板，因为这里的 dot 引用的是当前标签，而不是当前警报：

```
{{ 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 }}
```

您可以在第一个范围内和第二个范围之前定义一个名为 `$alert` 的变量来解决此问题：

```
{{ 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 }}
```

## 带索引的范围
<a name="v9-go-rangeindex"></a>

您可以在范围的开头定义 index 和 value 变量来获取范围内每个警报的索引：

```
{{ $num_alerts := len .Alerts }}
{{ range $index, $alert := .Alerts }}
This is alert {{ $index }} out of {{ $num_alerts }}
{{ end }}
```

## 定义模板
<a name="v9-go-define"></a>

您可以使用 `define` 和双引号中的模板名称来定义可在其他模板中使用的模板。定义的模板不能与其他模板同名，包括 `__subject`、`__text_values_list`、`__text_alert_list`、`default.title` 和 `default.message` 等默认模板。如果创建的模板与默认模板或其他通知模板中的模板同名，Grafana 可能会使用其中任何一个模板。当存在两个或多个同名模板时，Grafana 不会阻止或显示错误消息。

```
{{ define "print_labels" }}
{{ end }}
```

## 嵌入模板
<a name="v9-go-embed"></a>

您可以使用 `template`、双引号中的模板名称以及应传递给模板的光标在模板中嵌入定义的模板：

```
{{ template "print_labels" . }}
```

## 将数据传递给模板
<a name="v9-go-passdata"></a>

在模板中，dot 将引用传递给模板的值。

例如，如果向模板传递了触发警报列表，则 dot 引用该触发警报列表：

```
{{ template "print_alerts" .Alerts }}
```

如果模板传递了警报的排序标签，则 dot 引用已排序标签的列表：

```
{{ template "print_labels" .SortedLabels }}
```

这在编写可重用模板时很有用。例如，要打印所有警报，您可以编写以下内容：

```
{{ template "print_alerts" .Alerts }}
```

然后，如果仅打印触发警报，您可以这样编写：

```
{{ template "print_alerts" .Alerts.Firing }}
```

这是可以的，因为 `.Alerts` 和 `.Alerts.Firing` 都是警报列表。

```
{{ define "print_alerts" }}
{{ range . }}
{{ template "print_labels" .SortedLabels }}
{{ end }}
{{ end }}
```

## 评论
<a name="v9-go-comments"></a>

您可以使用 `{{/*` 和 `*/}}` 添加注释：

```
{{/* This is a comment */}}
```

要防止注释添加换行符，请使用：

```
{{- /* This is a comment with no leading or trailing line breaks */ -}}
```

## 缩进
<a name="v9-go-indentation"></a>

您可以使用缩进、制表符和空格以及换行符，来提高模板的可读性：

```
{{ range .Alerts }}
  {{ range .Labels.SortedPairs }}
    {{ .Name }} = {{ .Value }}
  {{ end }}
{{ end }}
```

但模板中的缩进也将出现在文本中。接下来，我们看如何将其移除。

## 移除空格和换行符
<a name="v9-go-removespace"></a>

正在 text/template 使用`{{-``-}}`并删除前导和尾随空格以及换行符。

例如，使用缩进和换行符来提高模板的可读性：

```
{{ range .Alerts }}
  {{ range .Labels.SortedPairs }}
    {{ .Name }} = {{ .Value }}
  {{ end }}
{{ end }}
```

缩进和换行符也将出现在文本中：

```
    alertname = "Test"

    grafana_folder = "Test alerts"
```

您可以移除文本中的缩进和换行符，将每个范围开始处的 `}}` 更改为 `-}}`：

```
{{ range .Alerts -}}
  {{ range .Labels.SortedPairs -}}
    {{ .Name }} = {{ .Value }}
  {{ end }}
{{ end }}
```

模板中的缩进和换行符现已从文本中消失：

```
alertname = "Test"
grafana_folder = "Test alerts"
```