内容模板语法(新版)

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

概述

相对于旧版的内容模板语法,新版通过类似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 }}