内容模板语法(新版)

内容模板语法(新版)

新版告警支持两个版本的内容模板语法。本文介绍新版内容模板语法。

概述

相对于旧版的内容模板语法,新版通过类似 Python 语法的方式,提供更加灵活且高级的自定义渲染逻辑,在定制通知内容(例如 Markdown 转义)、自定义内容样式等方面都做了优化,满足更多样化的定制内容需求。例如:

  • 根据告警的严重度进行动态的内容渲染,不同严重度使用不同颜色的文字进行区分。

  • 对告警的查询结果进行迭代渲染,在邮件中渲染为列表或者表格。

  • 通过函数对某个字段进行 BASE64 编码和解码、对数值进行数学运算等。

新版的内容模板语法完全兼容旧版,并支持新旧版混合使用。但在不同版本的内容模板语法中使用告警属性时,其类型、取值和展示形式等存在差异,因此建议您不要混合使用新旧版本的内容模板语法。推荐您使用新版本的内容模板语法。

快速开始

通过新版内容模板定义通知内容的示例如下:

  • 告警内容

    {
        "alert_id": "test-alert",
        "alert_name": "PV/UV Alert",
        "project": "project-1",
        "status": "firing",
        "severity": 6,
        "labels": {
            "app": "nginx",
            "host": "host-1"
        "results": [
                "project": "project-1",
                "logstore": "logstore-1",
                "query": "* | select count(*) as pv"
                "project": "project-2",
                "logstore": "logstore-2",
                "query": "* | select count(distinct user_id) as uv"
    }
  • 内容模板配置

    - Alert ID: {{ alert.alert_id }}
    - Alert Name: {{ alert.alert_name }}
    - Project: {{ alert.project }}
    - Status: {% if alert.status == "firing" %}FIRING{% else %}RESOLVED{% endif %}
    - Labels:
    {%- for key, val in alert.labels.items() %}
        - {{ key }}: {{ val }}
    {%- endfor %}
    - Query: {{ alert.results[0].query }}
  • 输出结果

    - Alert ID: test-alert
    - Alert Name: PV/UV Alert
    - Project: project-1
    - Status: FIRING
    - Labels:
        - app: nginx
        - host: host-1
    - Query: * | select count(*) as pv

基本语法

数据类型

内容模板语法类似于 Python 语法,支持如下数据类型。

数据类型

说明

数字

包含整数和浮点数。例如 3、-1。

字符串

需要使用单引号('')或者双引号("")包裹。例如"foo"、'bar'。

当字符串中存在特殊字符时,需使用反斜线(\)进行转义。例如 \foo 需写为 "\\foo"

布尔值

True、False。

空值

None。

列表

不同编程语言中的叫法不同,可以为列表、数组、Slice 等。例如['foo', 'bar']。

字典

不同编程语言中的叫法不同,可以为字典、对象等。例如{'foo': 'bar'}。

分隔符

分隔符

使用场景

示例

{{ }}

在变量或表达式中使用。

  • 数字: {{ 123 }}

  • 字符串: {{ "abc" }}或{{ 'xyz' }}

    需要使用双引号("")或单引号('')。

  • 变量: {{ alert.alert_name }}

  • 表达式: {{ alert.project + '/' + alert.alert_id }}

{% %}

用于控制语句。

{% if alert.status == 'firing' %}FIRING{% else %}RESOLVED{% endif % }

{# #}

用于注释,不会出现在通知内容中。

{# this is a comment #}

清除空字符

默认情况下,在分隔符内部,分隔符与表达式之间的空格会被忽略。例如 {{ 23 }} < {{ 45 }} 等同于 {{23}} < {{45}} ,渲染结果都为 23 < 45 。但是分隔符外部的空字符(空格、Tab、换行等)会被保留,例如 {{ 23 }} < {{ 45 }} 的渲染结果为 23 < 45 ,而不是 23<45

当您需要删除多余的空字符时,可以使用清除空字符操作。在分隔符开始或结束的地方添加一个短划线(-),用于清除该分隔符前面和后面所有紧连着的空字符。例如 {{ 23 -}} < {{- 45 }} 的渲染结果为 23<45

  • {{- {{%- {#- 用于删除分隔符左侧紧连着的所有空字符。

  • -}} -%} -%} 用于删除分隔符右侧紧连着的所有空字符。

重要
  • 短划线(-)和分隔符之间不能有空格。例如 {{- 3 }} 是有效的,渲染结果为 3 {{ - 3 }} 是无效的,渲染结果为 -3

  • 清除空字符操作只对分隔符外部的空格有效,不影响分隔符内部的空格。例如 {{ "hello " }} {{- "world"}} 渲染结果为 hello world

条件语句

条件判断支持对参数或者逻辑比较表达式进行判断。通过条件判断,可以进行动态渲染。

  • 如果 if 后面传入的是常量或者普通变量,则对该值进行真值判断。其中布尔值 false 、数字 0 、空字符串 "" 、空值 null 、空数组 [] 、空对象 {} 都会被判定为假,其它值被判定为真。

  • 如果 if 后面传入的是逻辑比较表达式,则按照比较结果进行判断。例如 {{ if alert.severity >= 8 }} 用于判断告警严重度是否大于等于 8。

条件判断支持如下几种形式:

使用方式

示例

if

{% if alert.severity >= 8 %}
{% endif %}

if-else

{% if alert.severity >= 8 %}
{% else %}
{% endif %}

if-elif

{% if alert.severity >= 8 %}
{% elif alert.severity >= 4 %}
{% endif %}

if-elif-else

{% if alert.severity >= 8 %}
{% elif alert.severity >= 4 %}
{% else %}
{% endif %}

嵌套使用

{% if alert.severity >= 8 %}
{% else %}
{% if alert.severity >= 4 %}
{% else %}
{% endif %}
{% endif %}

迭代

循环语句用于对数组和对象进行迭代操作。支持如下几种使用方式:

使用方式

示例

数组迭代

{% for result in alert.results %}
{{ result }}
{% endfor %}

数组迭代,包含下标

使用 enumerate 函数对数组进行下标迭代。关于 enumerate 函数的更多信息,请参见 enumerate 函数

{% for index, result in enumerate(alert.results) %}
{{ index }}: {{ result }}
{% endfor %}

下标默认从 0 开始。您也可以通过 enumerate 函数中的 start 参数自定义起始下标。例如:

{% for index, result in enumerate(alert.results, start=1) %}
{{ index }}: {{ result }}
{% endfor %}

对象迭代

通过 items()方法将对象转为 Key:Value 形式的数组进行迭代。

{% for key, val in alert.labels.items() %}
{{ key }}: {{ val }}
{% endfor %}

嵌套使用

{% for result in alert.fire_results %}
{% for key, val in result.items() %}
{{ key }}: {{ val }}
{% endfor %}
{% endfor %}

转义

如果您希望特殊字符串(例如 {{ )不被内容模板解析和渲染,可对特殊字符串进行转义。例如:根据如下配置表示保留 {% raw %} {% endraw %} 之间所有的内容。

  • 内容模板配置

    {% raw %}
    {% for result in alert.results %}
    {{ result }}
    {% endfor %}
    {% endraw %}
  • 结果

    {% for result in alert.results %}
    {{ result }}
    {% endfor %}

函数

内置模板函数便于您对数据进行各种操作,丰富了通知内容的格式和展示样式。更多信息,请参见 内置模板函数

例如您要通过 Webhook 方式发送 JSON 格式的内容,相关信息如下:

  • 告警的查询语句(包含一个换行)

    * |
    select count(*) as cnt
  • 不同使用方式的对比说明

    对比项

    内容模板

    结果

    说明

    不使用函数

    {
        "query": "{{ alert.results[0].query }}"
        "query": "* |
    select count(*) as pv"
    }

    JSON 格式不合法

    使用 quote 函数

    {
        "query": {{ quote(alert.results[0].query) }}
        "query": "* | \nselect count(*) as pv"
    }

    JSON 格式合法

过滤器

在函数嵌套使用场景中,通知内容的编辑麻烦且不够直观,例如 {{ block(to_list(alert.labels)) }} ,此时您可以使用过滤器功能。过滤器使用竖线(|) 操作符,并支持链式调用,一般格式为 {{ xxx | filiter1 | filter2 | ... }} 。例如 {{ blockquote(to_list(alert.labels)) }} 等同于 {{ alert.labels | to_list | blockquote }}

使用过滤器方式时,请先确认目标内置函数是否支持过滤器方式。大部分内置函数都支持过滤器方式的调用。更多信息,请参见 内置模板函数

重要
  • 如果函数中没有参数,则只能使用函数方式,不支持过滤器方式。

  • 当函数中只有一个参数时,推荐使用过滤器方式,即使用 {{ arg | fn }} 。例如 {{ abs(-1) }} 等同于 {{ -1 | abs }}

  • 如果函数中有多个参数,且从第二个参数开始有默认值,也可以使用过滤器。如果有多个参数值需要传递,通过过滤器方式并不直观。不建议对多参数的函数使用过滤器方式。

操作符

内容模板表达式中支持如下操作符。操作符的优先级说明请参见 Operator precedence

类别

操作符

说明

算数

+

加法

-

减法

*

乘法

/

除法,返回值是一个浮点数。

//

除法,返回整数。

%

取模

比较

==

等于

!=

不等于

>

大于

>=

大于等于

<

小于

<=

小于等于

逻辑

and

且操作

or

或操作

not

取反

其它

in

判断是否包含,返回布尔类型的结果。

  • 数组: {{ 1 in [1, 2, 3] }}

  • 对象: {{ "foo" in {"foo": "bar" } }}

  • 字符串: {{ "ll" in "hello" }}

()

操作组合,例如:{{ a > b and (a > c or b > c) }}

使用告警变量

在新版内容模板中,告警变量的使用形式为 alert.xxx ,例如 alert.project 。更多信息,请参见 内容模板变量说明(新版)

配置示例

  • 示例 1:根据告警状态展示不同内容

    触发告警后,展示告警状态、告警严重度和触发结果等信息;告警恢复时,只展示告警状态。

    • 不使用函数

      {% if alert.status == "firing" %}
      - 状态: <font color="#E03C39">触发</font>
      - 严重度:{{ alert.severity | format_severity }}
      - Results: {{ alert.results | to_json }}
      {% else %}
      - 状态: <font color="#72C140">恢复</font>
      {% endif %}
    • 使用函数

      使用 format_status 函数和 format_severity 函数简化配置。

      - 状态: {{ alert.status | format_status }}
      {% if alert.status == "firing" %}
      - 严重度:{{ alert.severity | format_severity }}
      - Results: {{ alert.results | to_json }}
      {% endif %}
  • 结构化数据展示

    将告警标签的内容转换为列表形式,内容为 Markdown 格式。

    • 不使用函数

      - 项目: {{ alert.project }}
      - 告警名称: {{ alert.alert_name }}
      - 告警标签:
      {%- for key, val in alert.labels.items() %}
      > - {{ key }}: {{ val }}
      {%- endfor %}
    • 使用函数

      使用 to_list 函数和 blockquote 函数简化配置。

      - 项目: {{ alert.project }}
      - 告警名称: {{ alert.alert_name }}
      - 告警标签:
      {{ alert.labels | to_list | blockquote }}