3 触发器表达式
概述
本页介绍触发器表达式的语法和求值细节。
简单表达式的语法为:
function(/host/item,time_period)<operator><constant>
在该表达式中,第一个操作数(位于运算符左侧)是一个带有括号中参数的函数(通常为数据监控项和时间周期)。
该函数用于分析设定时间周期内接收到的数据,并得出一个计算值。
然后使用运算符将该值与第二个操作数进行比较。在此示例中,第二个操作数是一个常量,但也可以是另一个函数。
例如:
min(/Zabbix server/net.if.in[eth0,bytes],5m)>100K
如果在最近五分钟内,eth0 上接收的字节数始终大于 100 KB,则该触发器会触发。在这种情况下,表达式为真,并会创建一个问题。
触发器表达式非常灵活。在更复杂的表达式中,可以组合多个函数、运算符和常量。
另请参见:
- 触发器示例
- 使用触发器进行问题检测(一般介绍)
函数
函数可用于分析已采集的值,例如计算平均值或查找特定字符串。
点击相应的函数组可查看更多详细信息。
| 函数组 | 函数 | |
|---|---|---|
| 聚合函数 | avg, bucket_percentile, count, histogram_quantile, item_count, kurtosis, mad, max, min, skewness, stddevpop, stddevsamp, sum, sumofsquares, varpop, varsamp | |
| Foreach 函数 | avg_foreach, bucket_rate_foreach, count_foreach, exists_foreach, last_foreach, max_foreach, min_foreach, sum_foreach | |
| 按位函数 | bitand, bitlshift, bitnot, bitor, bitrshift, bitxor | |
| 日期和时间函数 | date, dayofmonth, dayofweek, now, time | |
| 历史函数 | change, changecount, count, countunique, find, first, firstclock, fuzzytime, last, lastclock, logeventid, logseverity, logsource, logtimestamp, monodec, monoinc, nodata, percentile, rate | |
| 趋势函数 | baselinedev, baselinewma, trendavg, trendcount, trendmax, trendmin, trendstl, trendsum | |
| 数学函数 | abs, acos, asin, atan, atan2, avg, cbrt, ceil, cos, cosh, cot, degrees, e, exp, expm1, floor, log, log10, max, min, mod, pi, power, radians, rand, round, signum, sin, sinh, sqrt, sum, tan, truncate | |
| 运算符函数 | between, in | |
| 预测函数 | forecast, timeleft | |
| 字符串函数 | ascii, bitlength, bytelength, char, concat, insert, jsonpath, left, length, ltrim, mid, repeat, replace, right, rtrim, trim, xmlxpath | |
除非另有说明,这些函数支持用于:
Foreach 函数仅支持用于聚合计算。
通常,函数返回数值以供比较。 当返回字符串时,可使用 = 和 <> 运算符进行比较(请参见检测不同主机上的不匹配软件示例)。
函数参数
函数参数允许指定:
- 用于引用主机监控项历史记录的监控项键(格式为
/host/key) - 时间周期(以及其他特定于函数的参数)
- 其他表达式
监控项键值
被引用的监控项必须处于受支持状态(nodata() 函数除外,它也会对不受支持的监控项进行计算)。
在第一个参数中省略主机名(即如 function(//key,parameter,...))仅在特定上下文中受支持:
在这些上下文中,您还可以使用 {HOST.HOST} 宏。
在 事件名称 字段和“触发器”地图元素中,可以使用 {HOST.HOST<1-9>} 来引用触发器表达式中的特定监控项。
当在这些上下文中省略主机名或用 {HOST.HOST} 替换时,该引用将指向触发器表达式中的第一个监控项,或图形中的第一个监控项。
在这些受支持的上下文之外,在触发器表达式中省略主机名将导致错误。
有关在事件名称宏中使用双斜杠的示例,请参见 比较长期 CPU 负载。
时间段
函数专用参数放在监控项键值之后,并通过逗号与监控项键值分隔。
大多数数值函数都接受时间段作为参数。 它用于指定我们感兴趣的时间区间。 可以将其指定为时间段(30s、10m、1h),也可以指定为取值范围(#5 - 表示最近五个值)。
你可以使用秒或时间后缀来表示时间段。 如果参数前带有井号,其含义则不同:
| Expression | Description |
|---|---|
| sum(/host/key,10m) | 最近 10 分钟内各值的总和。 |
| sum(/host/key,#10) | 最近十个值的总和。 |
对于函数 last,带井号的参数含义又有所不同——它表示前第 N 个值。因此,给定值 30、70、20、60、50(从最近到最早):
last(/host/key,#2)将返回“70”last(/host/key,#5)将返回“50”
时间段是截至“now”来计算的——其中“now”是触发器最近一次重新计算的时间(参见计算频率);“now”并不是服务器的当前时间。
时间段指定以下两者之一:
- 考虑“now-time period”到“now”之间的所有值(或者,在使用 时间偏移时,考虑“now-time shift-time period”到 “now-time_shift”之间的所有值)
- 考虑从过去到“now”为止、不超过 num count 个值
- 如果在指定的时间段或 num count 内没有 0 个可用值, 则使用此函数的触发器或计算型监控项将变为不支持状态
请注意:
- 如果触发器中只使用了单个函数(引用历史数据),则“now”始终是最近一次接收到的值。例如,如果最后一个值是在一小时前接收到的,则时间段将被视为截至一小时前的最新值。
- 新触发器会在接收到第一个值后立即计算(历史函数);对于日期和时间函数以及nodata()函数,则会在 30 秒内计算。因此,即使自触发器创建以来,设定的时间段(例如一小时)可能尚未过去,触发器仍会被计算。即使时间范围被设置为例如最近十个值,触发器也会在接收到第一个值后进行计算。
时间偏移
支持将可选的时间偏移与时间或值计数一起作为函数参数使用。 该参数允许引用过去某一时间段内的数据。
时间偏移以 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。
| 参数 | 描述 |
|---|---|
| 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 Unknown → Unknown | 是 |
| 3 | * | 乘法 | 0 * Unknown → Unknown (是的,结果是 Unknown,而不是 0——这样可避免在算术运算中丢失 Unknown) 1.2 * Unknown → Unknown |
是 |
| / | 除法 | Unknown / 0 → error Unknown / 1.2 → Unknown 0.0 / Unknown → Unknown |
是 | |
| 4 | + | 算术加法 | 1.2 + Unknown → Unknown | 是 |
| - | 算术减法 | 1.2 - Unknown → Unknown | 是 | |
| 5 | < | 小于。该运算符定义为: A<B ⇔ (A<B-0.000001) |
1.2 < Unknown → Unknown | 是 |
| <= | 小于或等于。该运算符定义为: A<=B ⇔ (A≤B+0.000001) |
Unknown <= Unknown → Unknown | 是 | |
| > | 大于。该运算符定义为: A>B ⇔ (A>B+0.000001) |
是 | ||
| >= | 大于或等于。该运算符定义为: A>=B ⇔ (A≥B-0.000001) |
是 | ||
| 6 | = | 等于。该运算符定义为: A=B ⇔ (A≥B-0.000001) and (A≤B+0.000001) |
否 1 | |
| <> | 不等于。该运算符定义为: A<>B ⇔ (A<B-0.000001) or (A>B+0.000001) |
否 1 | ||
| 7 | and | 逻辑与 | 0 and Unknown → 0 1 and Unknown → Unknown Unknown and Unknown → Unknown |
是 |
| 8 | or | 逻辑或 | 1 or Unknown → 1 0 or Unknown → Unknown Unknown or Unknown → Unknown |
是 |
1 在以下情况下,字符串操作数仍会被转换为数值:
- 另一个操作数是数值
- 对操作数使用了 = 或 <> 以外的运算符
(如果转换失败,则数值操作数会被转换为字符串操作数,并将两个操作数作为字符串进行比较。)
not、and 和 or 运算符区分大小写,且必须使用小写。 它们还必须由空格或括号包围。
除一元 - 和 not 外,所有运算符都具有从左到右的结合性。 一元 - 和 not 是非结合的(这意味着应使用 -(-1) 和 not (not 1),而不是 --1 和 not not 1)。
求值结果:
- <、<=、>、>=、=、<> 运算符在指定关系为真时,应在触发器表达式中产生“1”,为假时产生“0”。 如果至少有一个操作数为 Unknown,则结果为 Unknown;
- 对于已知操作数,and 在其两个操作数都不等于“0”时产生“1”;否则产生“0”;对于未知操作数,and 仅当其中一个操作数等于“0”时产生“0”;否则产生“Unknown”;
- 对于已知操作数,or 在其任一操作数不等于“0”时产生“1”;否则产生“0”;对于未知操作数,or 仅当其中一个操作数不等于“0”时产生“1”;否则产生“Unknown”;
- 对于已知操作数,逻辑非运算符 not 的结果为:如果其操作数的值不等于“0”,则为“0”;如果其操作数的值等于“0”,则为“1”。 对于未知操作数,not 产生“Unknown”。
未知表达式状态
在以下情况下,触发器表达式中可能会出现未知操作数:
- 使用了不受支持的监控项
- 对于受支持的监控项,函数求值结果出错
在这种情况下,触发器表达式通常会被求值为 Unknown(因为它无法被计算)。
可以对未知触发器接收通知。
例外情况
尽管存在未知操作数,在某些情况下,触发器表达式仍可被求值为已知结果(Problem/OK):
- 无论被引用的监控项是否受支持,
nodata()函数都会被求值。 - 包含 AND/OR 的表达式在两种情况下可被求值为已知结果:
- 情况 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”)。
- 情况 1:
- 如果对受支持监控项的函数求值结果出错,则该函数值会变为
Unknown,并在后续表达式求值中作为未知操作数参与计算。
如上所述,未知操作数只可能在逻辑表达式中“消失”。
在算术表达式中,未知操作数始终会导致结果为 Unknown(除以 0 的情况除外)。
未知表达式状态不会改变触发器状态(Problem/OK)。
因此,如果触发器状态原本为“Problem”(见情况 1),即使已知部分已恢复(1 变为 0),它仍会保持 problem 状态,因为此时表达式会被求值为 Unknown,而这不会改变触发器状态。
如果包含多个不受支持监控项的触发器表达式被求值为 Unknown,则前端中的错误消息会指向最后一个被求值的不受支持监控项。
值缓存
触发器求值所需的值由 Zabbix 服务器缓存。 因此,在服务器重启后的一段时间内,触发器求值会导致数据库负载升高。
当监控项历史值被删除时(无论是手动删除还是由 housekeeper 删除),值缓存都不会被清除,因此服务器将继续使用缓存的值,直到这些值早于触发器函数中定义的时间段,或者服务器被重启。
如果缓存中没有最近的数据,并且函数中未定义查询时间段,Zabbix 默认会向过去最多回溯一周,从数据库中查询历史值。