2 触发器表达式

概述

触发器 中使用的表达式非常灵活。
您可以使用它们来创建有关受监控统计数据的复杂逻辑测试。

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

简单且实用的表达式语法为 function(/host/key,parameter)<operator><constant>

例如:

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

如果在最近五分钟内接收的字节数始终高于 100 KB,则会触发。

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

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

仅定义问题表达式时,该表达式将同时用作问题阈值和问题恢复阈值。
只要问题表达式的计算结果为 TRUE,就表示存在问题。
只要问题表达式的计算结果为 FALSE,问题就已解决。

当同时定义问题表达式和补充的恢复表达式时,问题解决会变得更复杂:不仅问题表达式必须为 FALSE,恢复表达式也必须为 TRUE。
这对于创建 hysteresis 并避免触发器抖动很有用。

在恢复表达式中使用 {TRIGGER.VALUE} 宏没有意义,因为该表达式只会在触发器处于“Problem”状态时进行计算。因此,在计算表达式时,{TRIGGER.VALUE} 始终会解析为“1”(表示“Problem”状态)。

函数

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

可查看完整的支持的函数列表。

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

函数参数

函数参数允许指定:

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

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

  • 在计算型监控项的公式中
  • 在表达式宏中,这些宏可用于:

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

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

虽然在触发器中,作为函数参数的其他触发器表达式仅限于非历史函数,但这一限制不适用于计算型监控项

函数特定参数

函数特定参数位于监控项键之后,并通过逗号与监控项键分隔。 有关这些参数的完整列表,请参见 支持的函数

大多数数值函数都接受时间作为参数。 您可以使用秒数或 时间后缀 来表示时间。 如果参数前带有井号,则其含义不同:

Expression Description
sum(/host/key,10m) 最近 10 分钟内的值之和。
sum(/host/key,#10) 最近 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) 将返回一天前某一小时的平均值。

以月 (M) 和年 (y) 指定的时间偏移仅支持 趋势函数。其他函数支持秒 (s)、分钟 (m)、小时 (h)、天 (d) 和周 (w)。

带绝对时间段的时间偏移

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

绝对时间段的时间偏移以 now 开始 - 表示当前时间,后跟任意数量的时间操作:/<time unit> - 定义该时间单位的开始和结束,例如,一天的午夜到午夜,+N<time unit>-N<time unit> - 用于增加或减少 N 个时间单位。

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

Parameter Description
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)

运算符

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

Priority Operator Definition Notes for unknown values Force cast operand to float 1
1 - 一元负号 -Unknown → Unknown Yes
2 not 逻辑非 not Unknown → Unknown Yes
3 * 乘法 0 * Unknown → Unknown
(yes, Unknown, not 0 - to not lose
Unknown in arithmetic operations)
1.2 * Unknown → Unknown
Yes
/ 除法 Unknown / 0 → error
Unknown / 1.2 → Unknown
0.0 / Unknown → Unknown
Yes
4 + 算术加法 1.2 + Unknown → Unknown Yes
- 算术减法 1.2 - Unknown → Unknown Yes
5 < 小于。该运算符定义为:

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

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

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

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

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

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

1 如果满足以下条件,字符串操作数仍会转换为数值:

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

对于关系运算符(<<=>>=):如果转换失败(例如在 "" 上),表达式将返回 Unknown(不会回退为字符串比较)。

对于相等运算符(=<>):如果转换失败,则按原始字符串进行比较。

notandor 运算符区分大小写,且必须使用小写。 它们前后还必须有空格或括号。

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

求值结果:

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

值缓存

触发器求值所需的值由 Zabbix 服务器缓存。 因此,在服务器重启后的一段时间内,触发器求值会导致数据库负载升高。

当监控项历史值被删除时(无论是手动删除还是由 housekeeper 删除),值缓存都不会被清除,因此服务器将继续使用缓存的值,直到这些值早于触发器函数中定义的时间段,或者服务器被重启。

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

触发器示例

示例 1

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

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

'/Zabbix server/system.cpu.load[all,avg1]' 给出了被监控参数的简短名称。它指定了服务器是“Zabbix server”,监控项的键值是"system.cpu.load[all,avg1]”。通过使用函数“last()”获取最新的值。最后,“>5”意味着当Zabbix server最新获取的处理器负载值大于5时触发器就会处于异常状态。

示例 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分钟内CPU负载都超过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

服务器网卡从 Internet 下载一个大文件。 min 函数的使用: min(/www.example.com/net.if.in[eth0,bytes],5m)>100K

在过去5分钟内,eth0上接收字节数大于100kb时,表达式为true。

示例 5

SMTP服务群集的两个节点都停止。 注意在一个表达式中使用两个不同的主机:

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

当两个SMTP服务器(smtp1.example.com 和 smtp2.example.com)的smtp服务关闭时为真。

示例 6

Zabbix 代理需要升级。 使用函数 find() :

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

如果 Zabbix 代理的版本为 beta8,则表达式为真。

示例 7

服务器无法访问。

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

如果主机“example.example.com” 在过去 30 分钟内超过 5 次无法访问,则表达式为真。

示例 8

最近 3 分钟内没有心跳。 使用函数 nodata() :

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

要使用这个触发器,'tick'必须定义成一个trapper陷阱器监控项。主机应该使用zabbix_sender定期发送这个监控项的数据。如果在180秒内没有接收到数据,则触发值变为异常状态。

注释 ‘nodata’可以在任何类型的监控项中使用。

示例 9

夜间的CPU负载

使用函数time():

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

触发器只能在晚上 (00:00-06:00) 将其状态更改为 true。

示例 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)除外。

示例 11

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

使用 fuzzytime() 函数:

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

当服务器 MySQL_DB 上的本地时间与 Zabbix 服务器时间相差超过 10 秒时,触发器将变为问题状态。 请注意,system.localtime 必须为 Zabbix agent 配置为 被动检查;在 Zabbix agent 2 上,它也可以配置为主动检查。

示例 12

比较今天的平均负载和昨天同一时间的平均负载(使用时移作为now-1d)。

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

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

示例 13

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

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

如果可用存储量低于 10%,触发器将触发。

示例 14

使用评估结果获取超过阈值的触发器数量:

(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

如果表达式中至少有两个触发器大于5,触发器将触发。

示例 15

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

问题:如果两台主机Ubuntu版本不同,则产生告警。

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

比较两个字符串值 - 操作数为:

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

问题:检测 DNS 查询中的变化

监控项键为:

net.dns.record[192.0.2.1,{$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 查询结果是否偏离预期结果的触发器表达式为:

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

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

示例 17

比较两个字符串值 - 操作数为:

  • 返回字符串的函数
  • 带有特殊字符 \ 和 " 的字符串常量

问题:检测 /tmp/hello 文件内容是否等于:

\" //hello ?\"

选项 1. 直接写入字符串:

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

请注意,当字符串直接比较时,\ 和 " 字符会如何被转义。

选项 2. 使用宏

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

在表达式中:

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

比较长期周期

问题: Load of Exchange server increased by more than 10% last month

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

您也可以在触发器配置中使用 事件名称 构建有意义的告警,例如, 接收信息如下:

"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 开发人员。

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

滞后

有时,问题和恢复状态之间需要一个间隔,而不是一个简单的阈值。例如,如果我们想定义一个触发器,它在服务器机房温度高于20°C时报告问题,并且我们想让它在温度低于15°C之前保持问题状态,那么简单的触发器阈值为20°C是不够的。

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

在这种情况下,问题恢复将分两步进行:

  • 首先,问题表达式(温度高于 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,则前端中的错误消息会引用最后一个被求值的不受支持监控项。