2 触发器表达式
概述
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 迟滞效应和避免触发器误报非常有用。
在恢复表达式中使用{TRIGGER.VALUE}宏是无效的,因为该表达式仅在触发器处于"Problem"状态时才会被评估。因此,在表达式评估过程中{TRIGGER.VALUE}始终会解析为"1"(表示"Problem"状态)。
函数
函数可用于计算采集值(平均值、最小值、最大值、总和)、查找字符串、引用当前时间及其他因素。
完整supported functions列表可供查阅。
通常函数会返回用于比较的数值。当返回字符串时,可使用=和<>运算符进行比较(参见示例)。
函数参数
函数参数允许指定:
- 主机和监控项键(仅引用主机监控项历史的函数)
- 函数特定参数
-
其他表达式(不适用于引用主机的函数)
item history, see other expressions for examples)
主机和监控项键可指定为/host/key。被引用的
监控项必须处于支持状态(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 未知 → 未知 | 是 |
| 3 | * | 乘法 | 0 * 未知 → 未知 (是的,未知,不是0 - 以避免在算术运算中丢失未知值) 1.2 * 未知 → 未知 |
是 |
| / | 除法 | Unknown / 0 → 错误 Unknown / 1.2 → Unknown 0.0 / Unknown → Unknown |
是 | |
| 4 | + | 算术加号 | 1.2 + 未知 → 未知 | 是 |
| - | 算术减号 | 1.2 - 未知 → 未知 | 是 | |
| 5 | < | 小于. 该运算符定义为: A<B ⇔ (A<B-0.000001) |
1.2 < Unknown → Unknown | 是 |
| <= | 小于或等于。该运算符定义为: A<=B ⇔ (A≤B+0.000001) |
Unknown <= Unknown → Unknown | Yes | |
| > | 大于. 该运算符定义为: 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 未知 → 1 0 or 未知 → 未知 未知 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 产生 '未知'。
值缓存
触发器评估所需的数值由Zabbix server进行缓存. 因此服务器重启后的一段时间内 触发器评估会导致数据库负载较高. 当监控项历史值被移除时(手动或通过housekeeper) value cache不会被清除 所以服务器将继续使用缓存值 直到这些值超过触发器函数中定义的时间周期或服务器重新启动.
触发器示例
示例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
当eth0网卡在过去5分钟内接收的字节数超过100KB时,该表达式为真.
示例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
如果主机 "example.example.com"在过去30分钟内超过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小时(周日23:00至周一01:00)。
示例 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的监控项值 - 此处操作数为返回字符串的函数
问题: 当Ubuntuversion在不同主机上不一致时create警报
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[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}"
注意第二个操作数周围的引号
示例 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)
您也可以在触发器配置中使用配置字段来构建有意义的告警消息, 例如接收类似
"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)。这可通过在defining触发器时设置恢复表达式参数实现。
此场景下问题恢复将分两步进行:
- 首先,问题表达式(温度高于20°C)必须评估为FALSE
-
其次,恢复表达式(温度低于15°C)必须
to evaluate to 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:表达式"
-
如果对受支持的监控项的函数评估导致错误,则
function value becomes
Unknownand it takes part as unknown operand in further expression evaluation.
Unknown,并作为未知操作数参与后续表达式评估。
请注意,未知操作数可能仅如上述逻辑表达式中所述"消失"。在算术表达式中,未知操作数总是导致结果为Unknown(除零除外)。
结果为Unknown的表达式不会改变触发器状态("Problem/OK")。
因此,如果它处于"Problem"状态(参见情况1),即使已知部分已解决('1'变为'0'),它仍保持相同的问题状态,因为表达式现在评估为Unknown,这不会改变触发器状态。
如果包含多个不支持的监控项的触发器表达式评估为Unknown,前端中的错误消息将引用最后评估的不支持的监控项。