2022 Zabbix中国峰会
2022 Zabbix中国峰会

2 触发器 表达式

概览

表达式在 触发器 中使用非常灵活,你可以使用表达式创建复杂的逻辑来测试监控统计。

一个简单的表达式使用函数,函数包括用到的监控项及参数,返回与阈值进行比较的结果,同时使用运算符和常量。

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

例如:

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

如果在最后五分钟期间接收到的网络字节数一直超过 100 KB 将触发。

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

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

当单独定义问题表达式时,该表达式同时被问题和问题恢复阈值使用。一旦问题表达式评估为TRUE,就触发一个问题,一旦问题表达式评估为FALSE,问题就被解决。

当定义了问题表达式和恢复表达式时,问题解决变得更加复杂,不仅仅问题表达式变为FALSE,而且恢复表达式评估为TRUE,这种情况对于创建 滞后 避免触发器振荡非常有用。

函数

函数可以计算采集值 (平均,最小,最大,求和), 查找字符串,参考当前时间和其他因素。

可用的完整支持列表见 支持函数

通常函数返回数值进行比较。当返回字符串时可以使用 =<> 操作符 进行比较 (参考 示例)。

函数参数

函数参数允许项:

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

主机和监控项键可以指定为 /host/key。被引用的监控项必须为支持状态 (函数 nodata() 除外,它是为不受支持的监控项计算的函数)。

尽管作为函数参数的其他触发器表达式受限于触发器中的非历史函数,但该限制不适用于 计算监控项

特定函数参数

特定函数参数放在监控项键的后面,使用逗号隔开,完整的参数列表参考 支持函数

大多数数值函数接受时间参数,你可以使用秒或 时间后缀 来表示时间。参数前有#标记,也代表不同的含义。

表达式 描述
sum(/host/key,10m) 最后10分钟的值求和。
sum(/host/key,#10) 最后10个值求和。

带有#的参数在last函数中有不同的含义, - 它表示第N个先前的值,因此给定值 3, 7, 2, 6, 5 (由近到远):

  • last(/host/key,#2) 将返回'7'
  • last(/host/key,#5) 将返回'5'
时间偏移

函数参数中时间或值计数支持时间偏移选项,该参数允许引用过去一段时间的数据。

时间偏移以 now 开头- 指当前时间,后接 +N<时间单位>-N<时间单位> - 加或减N个时间单位。

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

时间偏移中的月 (M) 和年 years (y) 仅支持 趋势函数. 其他函数支持 秒 (s), 分 (m), 时 (h), 天 (d), 和周 (w)。

绝对时间段的时间偏移

时间偏移参数中支持绝对时间段,例如,一天的午夜到午夜, 一周中的周一到周天,一个月的第一天到最后一天。

绝对时间段的时间偏移以 now 开始-指当前时间,后接任意数量的时间运算符: /<时间单位> - 定义开始和结束的时间单位,例如一天的午夜到午夜 +N<时间单位>-N<时间单位> - 加或减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)

运算符

触发器中支持以下运算符 (执行中优先级递减)

优先级 操作符 定义 注意unknown values 强制转换为浮点数 1
1 - -Unknown → Unknown Yes
2 not 逻辑非 not Unknown → Unknown Yes
3 * 0 * Unknown → Unknown
(yes, Unknown, not 0 - to not lose
算数运算中的Unknown)
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 字符串操作仍然转换为数字的情况如下:

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

(如果转换失败-数值操作数将转换为字符串操作数,并且两个操作数都将使用字符串来进行比较。)

not, andor 运算符区分大小写,并且必须为小写,他们必须用空格或括号包括起来。

除了 -not,所有运算符 具有从左至右的结合性。一元运算符 -not 是不具结合性 (意味着使用 -(-1)not (not 1) 代替 --1not not 1)。

评估结果:

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

值缓存

触发器评估所需的值由Zabbix server缓存。由于此触发器评估在服务器重新启动后一段时间导致较高的数据库负载。当监控项历史数据被移除(手动或管家)时,缓存值不会被清除,因此服务器将使用缓存的值,直到它们比触发器函数中定义的时间段或服务器重启的时间长。

触发器示例

示例 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))=1

当 /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 server之间的时间相差超过10秒,触发器将变为异常状态。 注意 'system.localtime' 必须配置为 被动检查.

示例 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.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查询结果是否与预期的结果有偏差的触发器表达式如下:

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

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

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

问题:检测/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)})

这种情况在触发器配置中允许手动关闭也很有用 。

滞后

有时,问题和恢复状态之间需要一个间隔,而不是一个简单的阈值。例如,如果我们想定义一个触发器,它在服务器机房温度高于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”,并作为未知操作数参与进一步的表达式评估。

请注意,未知操作数可能仅在上述逻辑表达式中“消失”。在算术表达式中,未知操作数始终导致结果“未知”(除以 0 外)。

结果为“未知”的表达式不会改变触发器状态(“问题/正常”)。 因此,如果它是“问题”(参见案例 1),即使已知部分得到解决(“1”变为“0”),它仍保持相同的问题状态,因为表达式现在被评估为“未知”,并且这不会改变触发器状态。

如果具有多个不受支持项的触发器表达式评估为“未知”,则前端中的错误消息指的是最后评估的不受支持项。

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