2 触发器表达式

概述

triggers中使用的表达式非常灵活。 您可以使用它们来create关于受监控统计信息的复杂逻辑测试。

一个简单的表达式使用一个函数,该函数带有一些参数应用于监控项。 该函数返回一个结果,该结果使用运算符和常量与阈值进行比较。

一个简单有用表达式的语法是 function(/host/key,parameter)<operator><constant>

例如:

仅返回OutputFormat格式要求结果 min(/Zabbix server/net.if.in[eth0,bytes],5m)>100K 仅返回OutputFormat格式要求结果 如果在最近五分钟内接收的字节数始终超过 100 千字节,则会触发。

虽然语法完全相同,但从功能角度来看,触发器表达式有两种类型:

  • 问题表达式 - 定义问题的条件
  • 恢复表达式(可选)— 定义问题解决的附加条件

在单独定义问题表达式时,此表达式将同时用作问题阈值和问题恢复阈值。 问题表达式一经计算为 TRUE,即表示存在问题。 问题表达式一旦评估为 FALSE,问题即告解决。

在同时定义问题表达式和补充恢复表达式时,问题的解决变得更为复杂:不仅问题表达式必须为假,恢复表达式也必须为真。 这对于 create 迟滞 并避免触发器抖动非常有用。

:::noteclassic 在恢复表达式中使用 {TRIGGER.VALUE} 宏是没有意义的,因为该表达式仅在触发器处于“问题”状态时进行评估。因此,在评估表达式时,{TRIGGER.VALUE} 始终会解析为 "1"(表示“问题”状态)。 仅返回OutputFormat格式要求结果

函数

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

完整的 supported functions 函数列表可用。

通常函数返回用于比较的数值。
当返回字符串时,可以使用 =<> 运算符进行比较(参见 示例)。

函数参数

函数参数允许指定:

  • 主机 和 监控项 键(仅适用于引用 主机 监控项 历史数据的函数)
  • 特定于函数的参数
  • 其他表达式(不适用于引用 主机 监控项 历史数据的函数,请参见 其他表达式 示例)

主机 和 监控项 键可以指定为 /host/key
在第一个参数中省略 主机 名称(例如 function(//key,parameter,...))仅在某些上下文中受支持:

  • 在计算型 监控项 的公式中
  • 在可在以下位置使用的表达式宏中:

在这些上下文中,还可以使用 {HOST.HOST} 宏。
事件名称 字段和 "Trigger" 地图元素中,可以使用 {HOST.HOST<1-9>} 来引用触发器表达式中的特定 监控项。
在这些上下文中,如果省略了 主机 名称或被 {HOST.HOST} 替代,则引用指向触发器表达式中的第一个 监控项 或图表中的第一个 监控项。
在这些受支持的上下文之外,在触发器表达式中省略 主机 名称将导致错误。
有关事件名称宏中双斜杠用法的示例,请参见 示例 18

被引用的 监控项 必须处于受支持的状态(nodata() 函数除外,该函数也可为不受支持的 监控项 计算)。

虽然触发器中的函数参数限制为非历史函数,但此限制不适用于 calculated items

函数特定参数

函数特定参数位于 监控项 键之后,并且与 监控项 键之间用逗号分隔。 有关这些参数的完整列表,请参见 supported functions

大多数数值函数接受时间作为参数。 您可以使用秒或 time 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'
时间偏移

支持使用时间或值数量作为函数参数进行可选的时间偏移。

该参数允许引用过去某一时间段的数据。

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

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

trend functions 支持以月 (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 本周
其他表达式

函数参数中可以包含其他表达式,语法如下所示:

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

请注意,如果函数引用了监控项的历史数据,则不能使用其他表达式。 例如,以下语法是不允许的:

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

运算符

支持以下触发器运算符 (按执行优先级从高到低排列)

优先级 运算符 定义 含有未知操作数的表达式的注意事项 强制转换操作数为 float 1
1 - 一元减号 -Unknown → Unknown
2 not 逻辑非 not Unknown → Unknown
3 * 乘法 0 * Unknown → Unknown
(是的,是 Unknown,而不是 0,以避免在算术运算中丢失
Unknown)
1.2 * Unknown → Unknown
/ 除法 Unknown / 0 → 错误
Unknown / 1.2 → Unknown
0.0 / Unknown → Unknown
4 + 算术加法 1.2 + Unknown → Unknown
- 算术减法 1.2 - Unknown → Unknown
5 < 小于。该运算符定义为:

A<B ⇔ (A<B-0.000001)
1.2 < Unknown → Unknown
<= 小于等于。该运算符定义为:

A<=B ⇔ (A≤B+0.000001)
Unknown <= Unknown → Unknown
> 大于。该运算符定义为:

A>B ⇔ (A>B+0.000001)
>= 大于等于。该运算符定义为:

A>=B ⇔ (A≥B-0.000001)
6 = 等于。该运算符定义为:

A=B ⇔ (A≥B-0.000001) 且 (A≤B+0.000001)
1
<> 不等于。该运算符定义为:

A<>B ⇔ (A<B-0.000001) 或 (A>B+0.000001)
1
7 and 逻辑与 0 and Unknown → 0
1 and Unknown → Unknown
Unknown and Unknown → Unknown
8 or 逻辑或 1 or Unknown → 1
0 or Unknown → Unknown
Unknown or Unknown → Unknown

1 如果满足以下条件,string 操作数仍将被强制转换为数字:

  • 另一个操作数是数字
  • 对操作数使用了除 =<> 以外的运算符

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

notandor 运算符是区分大小写的,必须使用小写。 它们还必须由空格或括号包围。

除一元 -not 外,所有运算符都具有从左到右的结合性。 一元 -not 是非结合的(意味着应使用 -(-1)not (not 1) 而不是 --1not not 1)。

运算结果:

  • 如果指定的关系为真,<<=>>==<> 运算符在触发器表达式中应返回 '1',如果为假则返回 '0'。 如果至少一个操作数是 Unknown,则结果为 Unknown;
  • 对于已知操作数,and 如果其两个操作数都不等于 '0',则返回 '1';否则返回 '0';对于未知操作数,and 如果其中一个操作数等于 '0',则返回 '0';否则返回 '未知';
  • 对于已知操作数,or 如果其任一操作数不等于 '0',则返回 '1';否则返回 '0';对于未知操作数,or 如果其中一个操作数不等于 '0',则返回 '1';否则返回 '未知';
  • 对于已知操作数,逻辑非运算符 not 如果其操作数不等于 '0',则返回 '0';如果其操作数等于 '0',则返回 '1'。 对于未知操作数,not 返回 '未知'。

值缓存

触发器评估所需的值由Zabbix server缓存。
由于这个原因,在服务器重启后的某个时间段内,触发器评估会导致数据库负载升高。
当监控项的历史值被移除时(无论是手动还是通过Housekeeper),value cache都不会被清除,因此服务器将继续使用缓存中的值,直到这些值的年龄超过触发器函数中定义的时间周期,或者服务器被重启。

如果缓存中没有最近的数据,并且函数中没有定义查询周期,则Zabbix默认会回溯最多一周的时间,以从数据库中query历史值。

触发器示例

示例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 状态。

示例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 时,该表达式为真。

示例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 等。

示例4

有人正在从互联网下载一个大型file。

min函数的使用:

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

当在最近的5分钟内,eth0接口接收的字节数超过100 KB时,该表达式为真。

示例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服务器均宕机时,该表达式为真。

示例6

Zabbix agent 需要升级。

使用函数 find():

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

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

示例 7

服务器不可达。

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

如果在最近 30 分钟内,主机 "example.example.com" 不可达超过 5 次,则此表达式为真。

示例 8

最近 3 分钟内没有心跳。

使用函数 nodata():

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

要使用此触发器,必须将 'tick' 定义为 Zabbix trapper 监控项。 主机 应该使用 zabbix_sender 定期发送此 监控项 的数据。 如果在 180 秒内未接收到数据,则触发器值变为 PROBLEM。

注意:'nodata' 可用于任何类型的 监控项。

示例 9

夜间 CPU 活动。

使用函数 time():

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

该触发器只能在夜间(00:00 - 06:00)改变其状态为问题。

示例 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:00 - 星期一,01:00)的 23 小时期间。

示例 11

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

使用fuzzytime()函数:

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

当MySQL_DB服务器上的本地时间与Zabbix server时间相差超过10秒时,触发器将变为问题状态。 请注意,'system.localtime'必须配置为一个被动检查

示例 12

将今天的平均负载与昨天同一时间的平均负载进行比较(使用时间偏移 now-1d)。

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

如果最近一小时的平均负载超过昨天同一小时平均负载的两倍,触发器将被触发。

示例 13

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

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

当可用存储空间低于 10 百分比时,触发器将被触发。

示例 14

使用评估结果来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

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

示例 15

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

问题:如果 Ubuntu 的 create 在不同的 主机 上的 version 不同,则触发告警。

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

比较两个 string 值 - 操作数包括:

  • 一个返回 string 的函数
  • 宏和字符串的组合

问题:检测 DNS query 的变化

对应的 监控项 键为:

net.dns.record[192.0.2.0,{$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[192.0.2.0,{$WEBSITE_NAME},{$DNS_RESOURCE_RECORD_TYPE},2,1])<>"{$WEBSITE_NAME}           {$DNS_RESOURCE_RECORD_TYPE}       0 mail.{$WEBSITE_NAME}"

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

示例 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}
示例 18

比较长期时间段。

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

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

此外,您还可以在触发器配置中使用Event name字段来构建有意义的告警信息。例如,以收到类似以下内容的消息:

"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)})

对于此类问题,在触发器配置中允许手动关闭也是很有用的。

有触发器表达式的示例可能对其他人有用?请使用示例建议表单将其发送给 Zabbix 开发人员。

迟滞

有时在问题状态和恢复状态之间需要一个间隔,而不仅仅是简单的阈值。
例如,如果我们希望定义一个触发器,当服务器机房温度超过 20°C 时报告问题,并且希望它保持在问题状态直到温度降至 15°C 以下,那么仅在 20°C 设置一个简单的触发器阈值是不够的。

相反,我们首先需要为问题事件定义一个触发器表达式(温度高于 20°C)。
然后我们需要定义一个额外的恢复条件(温度低于 15°C)。
这可以通过在 defining 触发器时定义一个额外的 恢复表达式 参数来实现。

在这种情况下,问题恢复将分为两个步骤:

  • 首先,问题表达式(温度高于 20°C)必须评估为 FALSE
  • 其次,恢复表达式(温度低于 15°C)必须评估为 TRUE

只有当问题事件首先被解决时,才会评估恢复表达式。

如果问题表达式仍然为 TRUE,仅恢复表达式为 TRUE 并不会解决该问题!

示例1

服务器机房温度过高。

问题表达式:

last(/server/temp)>20

恢复表达式:

last(/server/temp)<=15
示例2

可用磁盘空间过低。

问题表达式:最近 5 分钟内小于 10GB

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

恢复表达式:最近 10 分钟内大于 40GB

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

含有未知操作数的表达式

通常情况下,表达式中出现未知操作数(例如不支持的 监控项)会立即将触发器值设为 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
  • 如果对受支持的 监控项 进行函数求值时出现错误,则该函数值将变为 Unknown,并在进一步的表达式求值中作为未知操作数参与运算。

请注意,未知操作数仅在如上所述的逻辑表达式中可能“消失”。
在算术表达式中,未知操作数总是会导致结果为 Unknown(除以 0 的情况除外)。

如果一个表达式求值结果为 Unknown,则不会更改触发器的状态("Problem/OK")。
因此,如果之前是 "Problem"(参见情况 1),即使已知部分已解决('1' 变为 '0'),表达式现在求值为 Unknown,触发器状态仍保持不变。

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