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(不会回退为字符串比较)。
对于相等运算符(=、<>):如果转换失败,则按原始字符串进行比较。
not、and 和 or 运算符区分大小写,且必须使用小写。 它们前后还必须有空格或括号。
除一元 - 和 not 外,所有运算符都具有从左到右的结合性。 一元 - 和 not 是非结合的(这意味着应使用 -(-1) 和 not (not 1),而不是 --1 和 not 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。
- 情况 1:"
- 如果对受支持监控项的函数求值出错,则函数值会变为
Unknown,并在后续表达式求值中作为未知操作数参与计算。
请注意,未知操作数只有在上述逻辑表达式中才可能“消失”。
在算术表达式中,未知操作数始终会导致结果为 Unknown(除以 0 的情况除外)。
求值结果为 Unknown 的表达式不会改变触发器状态("Problem/OK")。
因此,如果它原本是 "Problem"(参见情况 1),即使已知部分恢复('1' 变为 '0'),它仍会保持在相同的问题状态,因为此时表达式会被求值为 Unknown,而这不会改变触发器状态。
如果包含多个不受支持监控项的触发器表达式求值为 Unknown,则前端中的错误消息会引用最后一个被求值的不受支持监控项。