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作为字符串进行比较。)

notandor运算符区分大小写且必须保持原样 小写。它们还必须被空格或括号包围。

除一元运算符 -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
  • 如果对受支持的监控项的函数评估导致错误,则

    function value becomes Unknown and it takes part as unknown operand in further expression evaluation.

Unknown,并作为未知操作数参与后续表达式评估。

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

结果为Unknown的表达式不会改变触发器状态("Problem/OK")。 因此,如果它处于"Problem"状态(参见情况1),即使已知部分已解决('1'变为'0'),它仍保持相同的问题状态,因为表达式现在评估为Unknown,这不会改变触发器状态。

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