[comment]: # translation:outdated

[comment]: # ({510ac9cc-510ac9cc})
# 2 触发器表达式

[comment]: # ({/510ac9cc-510ac9cc})

[comment]: # ({107cd0e3-473bcd5e})
#### 概述

[triggers](/manual/config/triggers)中使用的表达式具有极高的灵活性。您可以通过它们create关于监控统计数据的复杂逻辑测试。

简单表达式使用一个**函数**，该函数以特定参数作用于监控项。函数返回的结果会通过运算符与常量阈值进行比较。

基础有效表达式的语法为
`function(/host/key,parameter)<operator><constant>`。

例如：

      min(/Zabbix server/net.if.in[eth0,bytes],5m)>100K

将在过去五分钟内接收的字节数持续超过100千字节时触发。

虽然语法完全相同，但从功能角度来看，触发器表达式分为两种类型：

-   问题表达式 - 定义问题触发条件
-   恢复表达式（可选） - 定义问题解决的附加条件

    the problem resolution

当仅定义问题表达式时，该表达式将同时用作问题触发和恢复的阈值。一旦表达式评估为TRUE即触发问题，评估为FALSE则问题解决。

当同时定义问题表达式和补充恢复表达式时，问题解决逻辑会变得更复杂：不仅问题表达式需要评估为FALSE，恢复表达式也必须评估为TRUE。这对于create [迟滞效应](#hysteresis)和避免触发器误报非常有用。

:::noteclassic
在恢复表达式中使用{TRIGGER.VALUE}宏是无效的，因为该表达式仅在触发器处于"Problem"状态时才会被评估。因此，在表达式评估过程中{TRIGGER.VALUE}始终会解析为"1"（表示"Problem"状态）。

:::

[comment]: # ({/107cd0e3-473bcd5e})

[comment]: # ({d4e5ef03-d4e5ef03})
#### 函数

函数可用于计算采集值(平均值、最小值、最大值、总和)、查找字符串、引用当前时间及其他因素。

完整[supported functions](/manual/appendix/functions)列表可供查阅。

通常函数会返回用于比较的数值。当返回字符串时，可使用**=**和**<>**运算符进行比较(参见[示例](#example_14))。

[comment]: # ({/d4e5ef03-d4e5ef03})

[comment]: # ({b255de16-b255de16})
#### 函数参数

函数参数允许指定：

-   主机和监控项键（仅引用主机监控项历史的函数）
-   函数特定参数
-   其他表达式（不适用于引用主机的函数）

    item history, see [other expressions](#other_expressions) for
    examples)

主机和监控项键可指定为`/host/key`。被引用的
监控项必须处于支持状态（**nodata()**函数除外，
该函数对不受支持的监控项也会进行计算）。

虽然作为函数参数的其他触发器表达式在触发器中仅限于
非历史函数，但此限制不适用于
[calculated items](/manual/config/items/itemtypes/calculated)。

[comment]: # ({/b255de16-b255de16})

[comment]: # ({030f6133-cf9e09bb})
##### 函数特定参数

函数特定参数位于监控项键之后
并通过逗号与监控项键分隔。完整参数列表请参阅[supported
functions](/manual/appendix/functions)

大多数数值函数接受时间参数。可使用
秒数或[time suffixes](/manual/appendix/suffixes)表示时间。
以井号开头的参数具有不同含义：

| 表达式 | 描述 |
|----------|-----------|
| **sum**(/主机/key,**10m)** | 最近10分钟内的数值总和 |
| **sum**(/主机/key,**\#10)** | 最近十个数值的总和 |

带井号的参数在**last**函数中
具有不同含义 - 表示第N个前值，例如给定数值序列30, 70,
20, 60, 50（从最新到最旧）：

-   `last(/host/key,#2)` 将返回'70'
-   `last(/host/key,#5)` 将返回'50'

[comment]: # ({/030f6133-cf9e09bb})

[comment]: # ({983388a2-6699e631})
##### 时间偏移

可选的时间偏移支持以时间或数值计数作为函数参数。该参数允许引用过去某段时间的数据。

时间偏移以`now`开头表示当前时间，后接`+N<time unit>`或`-N<time unit>`用于加减N个时间单位。

例如，`avg(/host/key,1h:now-1d)`将返回一天前一小时的平均值。

::: noteimportant
仅[trend functions](/manual/appendix/functions/trends)支持以月(M)和年(y)为单位的时间偏移。
其他函数支持秒(s)、分钟(m)、小时(h)、天(d)和周(w)。

:::

**绝对时间段的时间偏移**

时间偏移参数支持绝对时间段，例如一天的午夜至午夜、一周的周一到周日、一个月的首日至末日。

绝对时间段的时间偏移以`now`开头表示当前时间，后接任意数量的时间操作：
`/<time unit>`定义时间单位的起止点(例如一天的午夜至午夜)，`+N<time unit>`或`-N<time unit>`用于加减N个时间单位。

请注意时间偏移值可以大于或等于0，而时间段的最小值为1。

| 参数 | 描述 |
|--|--------|
| 1d:now/d | 昨天   |
| 1d:now/d+1d | 今天       |
| 2d:now/d+1d | 最近2天 |
| 1w:now/w | 上周   |
| 1w:now/w+1w | 本周   |

[comment]: # ({/983388a2-6699e631})

[comment]: # ({c5d3ec54-c5d3ec54})
##### 其他表达式

函数参数可包含其他表达式，如下列语法所示：

    min(min(/host/key,1h),min(/host2/key2,1h)*10)

需注意若函数引用监控项历史数据，则不可使用其他表达式。例如下列语法不被允许：

~~`min(/host/key,#5*10)`~~

[comment]: # ({/c5d3ec54-c5d3ec54})

[comment]: # ({6f8e2042-10bc91a2})
#### 运算符

触发器支持以下运算符（按优先级降序排列）：
执行优先级)**：

| 优先级 | 运算符 | 定义 | **关于[含有未知操作数的表达式](/manual/config/triggers/expression#含有未知操作数的表达式)的注意事项** | 强制转换操作数为float ^**1**^ |
|-|-|----|----------------|--|
| **1**    | **-**    | 一元减号 | **-**Unknown → Unknown                                                                         | 是                             |
| **2**    | **not**  | 逻辑非 | **not** 未知 → 未知                                                                      | 是                             |
| **3**    | **\***   | 乘法 | 0 **\*** 未知 → 未知<br>(是的，未知，不是0 - 以避免在算术运算中丢失未知值)<br>1.2 **\*** 未知 → 未知 | 是                             |
| <        | **/**    | 除法       | Unknown **/** 0 → 错误<br>Unknown **/** 1.2 → Unknown<br>0.0 **/** Unknown → Unknown          | 是                             |
| **4**    | **+**    | 算术加号 | 1.2 **+** 未知 → 未知                                                                    | 是                             |
| <        | **-**    | 算术减号 | 1.2 **-** 未知 → 未知                                                                    | 是                             |
| **5**    | **\<**   | 小于. 该运算符定义为:<br><br>A<B ⇔ (A<B-0.000001) | 1.2 **<** Unknown → Unknown                                                                    | 是                             |
| <        | **<=**   | 小于或等于。该运算符定义为：<br><br>A<=B ⇔ (A≤B+0.000001) | Unknown **<=** Unknown → Unknown                                                               | Yes                             |
| <        | **>**    | 大于. 该运算符定义为:<br><br>A>B ⇔ (A>B+0.000001) |                                                                                                | 是                             |
| <        | **>=**   | 大于或等于。该运算符定义为：<br><br>A>=B ⇔ (A≥B-0.000001) |                                                                                                | 是                             |
| **6**    | **=**    | 等于。该运算符定义为：<br><br>A=B ⇔ (A≥B-0.000001) 且 (A≤B+0.000001) |                                                                                                | 否 ^**1**^                      |
| <        | **<>**   | 不等于。该运算符定义为：<br><br>A<>B ⇔ (A<B-0.000001) 或 (A>B+0.000001) |                                                                                                | 否 ^**1**^                      |
| **7**    | **and**  | 逻辑与 | 0 **and** Unknown → 0<br>1 **and** Unknown → Unknown<br>Unknown **and** Unknown → Unknown      | 是                             |
| **8**    | **or**   | 逻辑或 | 1 **or** 未知 → 1<br>0 **or** 未知 → 未知<br>未知 **or** 未知 → 未知         | 是                             |

^**1**^ string 操作数在以下情况下仍会被强制转换为数值类型：

-   另一个操作数为数值
- 操作数上使用了除 **=** 或 **<>** 以外的运算符

如果转换失败 - 数字操作数将被转换为string操作数
两个操作数get作为字符串进行比较。)

**not**、**and**和**or**运算符区分大小写且必须保持原样
小写。它们还必须被空格或括号包围。

除一元运算符 **-** 和 **not** 外，所有运算符均遵循从左到右的结合顺序
关联性。一元运算符 **-** 和 **not** 是非结合的（意味着
**-(-1)** 和 **not (not 1)** 应该被使用，而不是 **--1** 和
**非非 1**).

评估结果

-   **<**, **<=**, **>**, **>=**, **=**, **<>**
    操作符在触发器表达式中应产生'1'如果满足指定条件
    关系为真时返回'1'，为假时返回'0'。若至少有一个操作数为
    Unknown the result is Unknown;
未知的结果是未知;
-   **且** 对于已知操作数，当两个操作数均为真时结果为'1'
    比较不等于'0'；否则返回'0'；对于未知情况
    操作数 **and** 仅在其中一个操作数比较相等时产生'0'
    '0'；否则，它将产生'未知'；
-   **或** 对于已知操作数，如果任一操作数为'1'则结果为'1'
    比较不等于'0'；否则返回'0'；对于未知情况
    操作数 **or** 仅在其中一个操作数比较不等时才会产生'1'
    '0'；否则，它将产生'未知'；
-   逻辑非运算符 **not** 对已知值的结果
    操作数为'0'当其操作数的值比较不等于'0'时
    如果其操作数的值等于'0'则返回'1'. 对于未知值
    操作数 **not** 产生 '未知'。

[comment]: # ({/6f8e2042-10bc91a2})

[comment]: # ({195c3f4f-195c3f4f})
#### 值缓存

触发器评估所需的数值由Zabbix server进行缓存.
因此服务器重启后的一段时间内 触发器评估会导致数据库负载较高. 当监控项历史值被移除时(手动或通过housekeeper)
value cache不会被清除 所以服务器将继续使用缓存值 直到这些值超过触发器函数中定义的时间周期或服务器重新启动.

[comment]: # ({/195c3f4f-195c3f4f})

[comment]: # ({abac99e3-abac99e3})
#### 触发器示例

[comment]: # ({/abac99e3-abac99e3})

[comment]: # ({17b607dc-17b607dc})
##### 示例1

Zabbix server上的处理器负载过高。

    last(/Zabbix server/system.cpu.load[all,avg1])>5

通过使用函数'last()'，我们引用最近的值。`/Zabbix server/system.cpu.load[all,avg1]`给出被监控参数的简称。它指定主机为'Zabbix server'，且被监控的键是'system.cpu.load\[all,avg1\]'。最后，`>5`表示当Zabbix server最近的处理器负载测量值大于5时，触发器将处于PROBLEM状态。

[comment]: # ({/17b607dc-17b607dc})

[comment]: # ({9a129732-9a129732})
##### 示例2

www.example.com 已过载.

    last(/www.example.com/system.cpu.load[all,avg1])>5 or min(/www.example.com/system.cpu.load[all,avg1],10m)>2 

当当前处理器负载超过5或过去10分钟内处理器负载超过2时,表达式为真.

[comment]: # ({/9a129732-9a129732})

[comment]: # ({8710cd40-49592749})
##### 示例3

/etc/passwd 文件已被修改.

    last(/www.example.com/vfs.file.cksum[/etc/passwd],#1)<>last(/www.example.com/vfs.file.cksum[/etc/passwd],#2)

当 /etc/passwd 校验和的前一个值与最新值不同时,该表达式为真.

类似的表达式可用于监控重要文件的变更,例如 /etc/passwd, /etc/inetd.conf, /kernel 等.

[comment]: # ({/8710cd40-49592749})

[comment]: # ({46e72843-46e72843})
##### 示例4

有人正在从互联网下载大型file.

函数min的使用:

    min(/www.example.com/net.if.in[eth0,bytes],5m)>100K

当eth0网卡在过去5分钟内接收的字节数超过100KB时，该表达式为真.

[comment]: # ({/46e72843-46e72843})

[comment]: # ({7956e04e-7956e04e})
##### 示例5

集群SMTP服务器的两个节点均宕机.

注意在一个表达式中使用了两个不同的主机:

    last(/smtp1.example.com/net.tcp.service[smtp])=0 and last(/smtp2.example.com/net.tcp.service[smtp])=0

当smtp1.example.com和smtp2.example.com上的两个SMTP服务器都宕机时，该表达式为真.

[comment]: # ({/7956e04e-7956e04e})

[comment]: # ({62cfb014-62cfb014})
##### 示例6

Zabbix agent 需要升级。

函数 find() 的使用：

    find(/example.example.com/agent.version,,"like","beta8")=1

如果 Zabbix agent 具有 version beta8，则表达式为真。

[comment]: # ({/62cfb014-62cfb014})

[comment]: # ({567b88a9-567b88a9})
##### 示例 7

服务器不可达。

    count(/example.example.com/icmpping,30m,,"0")>5

如果主机 "example.example.com"在过去30分钟内超过5次不可达，则该表达式为真。

[comment]: # ({/567b88a9-567b88a9})

[comment]: # ({2f13cb92-2f13cb92})
##### 示例 8

过去3分钟内无心跳信号。

函数nodata()的用法：

    nodata(/example.example.com/tick,3m)=1

要使此触发器生效，必须将'tick'定义为Zabbix
[trapper](/manual/config/items/itemtypes/trapper) 监控项。主机应
定期使用zabbix\_sender为此监控项发送数据。如果在180秒内未收到任何数据，
触发器值将变为PROBLEM。

*注意*：'nodata'可用于任何监控项类型。

[comment]: # ({/2f13cb92-2f13cb92})

[comment]: # ({8fe70766-2c48905a})
##### 示例 9

夜间CPU活动情况

使用time()函数:

    min(/Zabbix server/system.cpu.load[all,avg1],5m)>2 and time()<060000

该触发器仅在夜间时段(00:00 - 06:00)可能将其状态更改为问题状态

[comment]: # ({/8fe70766-2c48905a})

[comment]: # ({a6c0840e-7e0ba13a})
##### 示例 10

CPU活动在任何时间都可能出现异常。

使用time()函数和**not**运算符的情况：

    min(/zabbix/system.cpu.load[all,avg1],5m)>2
    and not (dayofweek()=7 and time()>230000)
    and not (dayofweek()=1 and time()<010000)

触发器可能在任何时间改变状态为问题状态，
除了一周交替时的2小时（周日23:00至周一01:00）。

[comment]: # ({/a6c0840e-7e0ba13a})

[comment]: # ({409b4657-0e6bfc51})
##### 示例 11

检查客户端本地时间是否与Zabbix server时间同步.

使用fuzzytime()函数:

    fuzzytime(/MySQL_DB/system.localtime,10s)=0

当MySQL\_DB服务器本地时间与Zabbix server时间相差超过10秒时，触发器将切换至问题状态。注意'system.localtime'必须配置为[被动检查](/manual/appendix/items/activepassive#被动检查).

[comment]: # ({/409b4657-0e6bfc51})

[comment]: # ({9efdd3fc-47b2e2fd})
##### 示例 12

将今日平均负载与昨日同一时刻的平均负载进行比较（使用时间偏移`now-1d`）。

    avg(/server/system.cpu.load,1h)/avg(/server/system.cpu.load,1h:now-1d)>2

如果最近一小时的平均负载超过昨日同一小时平均负载的两倍以上，此触发器将触发。

[comment]: # ({/9efdd3fc-47b2e2fd})

[comment]: # ({f40f2b77-bb0f5278})
##### 示例 13

使用另一个监控项的值来get触发器阈值:

    last(/Template PfSense/hrStorageFree[{#SNMPVALUE}])<last(/Template PfSense/hrStorageSize[{#SNMPVALUE}])*0.1

如果空闲存储空间降至10%以下，触发器将触发。

[comment]: # ({/f40f2b77-bb0f5278})

[comment]: # ({4a0b6e62-0cc34ec7})
##### 示例 14

使用[评估结果](#operators)来get超过阈值的触发器数量：

    (last(/server1/system.cpu.load[all,avg1])>5) + (last(/server2/system.cpu.load[all,avg1])>5) + (last(/server3/system.cpu.load[all,avg1])>5)>=2

如果表达式中至少有两个触发器处于问题状态，该触发器将会触发。

[comment]: # ({/4a0b6e62-0cc34ec7})

[comment]: # ({37eb6db6-adfc6b9d})
##### 示例 15

比较两个string的监控项值 - 此处操作数为返回字符串的函数

问题: 当Ubuntuversion在不同主机上不一致时create警报

    
last(/NY Zabbix server/vfs.file.contents[/etc/os-release])<>last(/LA Zabbix server/vfs.file.contents[/etc/os-release])

[comment]: # ({/37eb6db6-adfc6b9d})

[comment]: # ({f3a35db5-c2b4949f})
##### 示例 16

比较两个string值 - 操作数为:

-   返回string的函数
-   宏与字符串的组合

问题: 检测DNS query中的变更

监控项键为:

    net.dns.record[8.8.8.8,{$WEBSITE_NAME},{$DNS_RESOURCE_RECORD_TYPE},2,1]

宏定义为

    {$WEBSITE_NAME} = example.com
    {$DNS_RESOURCE_RECORD_TYPE} = MX

通常返回:

    example.com           MX       0 mail.example.com

因此我们检测DNS query结果是否偏离预期结果的触发器表达式为:

    last(/Zabbix server/net.dns.record[8.8.8.8,{$WEBSITE_NAME},{$DNS_RESOURCE_RECORD_TYPE},2,1])<>"{$WEBSITE_NAME}           {$DNS_RESOURCE_RECORD_TYPE}       0 mail.{$WEBSITE_NAME}"

注意第二个操作数周围的引号

[comment]: # ({/f3a35db5-c2b4949f})

[comment]: # ({6ae6282c-60fad4fc})
##### 示例 17

比较两个string值 - 操作数为:

-   返回string的函数
-   包含特殊字符\\和"的string常量

问题: 检测`/tmp/hello` file内容是否等于:

    \" //hello ?\"

选项1) 直接写入string

    last(/Zabbix server/vfs.file.contents[/tmp/hello])="\\\" //hello ?\\\""

注意当直接比较string时，\\和"字符是如何被转义的

选项2) 使用宏

    {$HELLO_MACRO} = \" //hello ?\"

在表达式中:

    
last(/Zabbix server/vfs.file.contents[/tmp/hello])={$HELLO_MACRO}

[comment]: # ({/6ae6282c-60fad4fc})

[comment]: # ({88460166-6906462b})
##### 示例 18

对比长期时间段.

问题: 上个月Exchange服务器负载增长超过10%

    trendavg(/Exchange/system.cpu.load,1M:now/M)>1.1*trendavg(/Exchange/system.cpu.load,1M:now/M-1M)

您也可以在触发器配置中使用[配置](/manual/config/triggers/trigger#配置)字段来构建有意义的告警消息, 例如接收类似

`"Load of Exchange server increased by 24% in July (0.69) comparing to June (0.56)"`

的事件名称必须定义为:

    Load of {HOST.HOST} server increased by {{?100*trendavg(//system.cpu.load,1M:now/M)/trendavg(//system.cpu.load,1M:now/M-1M)}.fmtnum(0)}% in {{TIME}.fmttime(%B,-1M)} ({{?trendavg(//system.cpu.load,1M:now/M)}.fmtnum(2)}) comparing to {{TIME}.fmttime(%B,-2M)} ({{?trendavg(//system.cpu.load,1M:now/M-1M)}.fmtnum(2)})

对于这类问题, 在触发器配置中允许手动关闭也很有用.

[comment]: # ({/88460166-6906462b})

[comment]: # ({3f1b1c81-3f1b1c81})
#### 迟滞

有时问题状态与恢复状态之间需要间隔，而非简单阈值。例如，若需定义一个触发器在机房温度超过20°C时报告问题，并希望问题状态持续到温度降至15°C以下，仅设置20°C的简单触发阈值是不够的。

此时需要先定义问题事件的触发表达式（温度高于20°C），然后定义额外的恢复条件（温度低于15°C）。这可通过在[defining](/manual/config/triggers/trigger)触发器时设置*恢复表达式*参数实现。

此场景下问题恢复将分两步进行：

-   首先，问题表达式（温度高于20°C）必须评估为FALSE
-   其次，恢复表达式（温度低于15°C）必须

    to evaluate to TRUE

恢复表达式仅在问题事件首次解决后才会被评估。

::: notewarning
若问题表达式仍为TRUE，仅恢复表达式为TRUE并不会解决问题！

:::

[comment]: # ({/3f1b1c81-3f1b1c81})

[comment]: # ({942a7e0e-942a7e0e})
##### 示例1

服务器机房温度过高

问题表达式:

    last(/server/temp)>20

恢复表达式:

    
last(/server/temp)<=15

[comment]: # ({/942a7e0e-942a7e0e})

[comment]: # ({bddf0717-bddf0717})
##### 示例2

磁盘剩余空间过低。

问题表达式：过去5分钟内小于10GB

    max(/server/vfs.fs.size[/,free],5m)<10G

恢复表达式：过去10分钟内大于40GB

    
min(/server/vfs.fs.size[/,free],10m)>40G

[comment]: # ({/bddf0717-bddf0717})

[comment]: # ({4158a8e3-6fc2eb1c})
#### 含有未知操作数的表达式

通常情况下，表达式中的未知操作数（例如不支持的监控项）会立即将触发器值设置为`Unknown`。

然而，在某些情况下，表达式计算允许存在未知操作数（不支持的监控项、函数错误）：

-   无论引用的监控项是否受支持，`nodata()`函数都会被评估。
-   带有OR和AND的逻辑表达式在以下两种情况下可以得出已知值，即使存在未知操作数：
    -   **情况1**：表达式"`1 or some_function(unsupported_item1) or some_function(unsupported_item2) or ...`"可以得出已知结果（'1'或"Problem"），
    -   **情况2**：表达式"`0 and some_function(unsupported_item1) and some_function(unsupported_item2) and ...`"可以得出已知结果（'0'或"OK"）。\
        Zabbix尝试通过将不支持的监控项视为未知操作数来评估此类逻辑表达式。在上述两种情况下会产生已知值（分别为"Problem"或"OK"）；在**所有其他**情况下，触发器将评估为`Unknown`。
-   如果对受支持的监控项的函数评估导致错误，则

    function value becomes `Unknown` and it takes part as unknown operand 
    in further expression evaluation.

`Unknown`，并作为未知操作数参与后续表达式评估。

请注意，未知操作数可能仅如上述逻辑表达式中所述"消失"。在算术表达式中，未知操作数总是导致结果为`Unknown`（除零除外）。

::: noteimportant
结果为`Unknown`的表达式不会改变触发器状态（"Problem/OK"）。
因此，如果它处于"Problem"状态（参见情况1），即使已知部分已解决（'1'变为'0'），它仍保持相同的问题状态，因为表达式现在评估为`Unknown`，这不会改变触发器状态。

:::

如果包含多个不支持的监控项的触发器表达式评估为`Unknown`，前端中的错误消息将引用最后评估的不支持的监控项。

[comment]: # ({/4158a8e3-6fc2eb1c})
