# Triggers and Prefilters
# Prefilter
# Supported operators
Operator | Description | Usage example |
---|---|---|
and | AND | _labels.type == 'Prometheus' and _stream.id == 10 |
or | OR | _stream.id == 10 or _stream.id == 11 |
not | NOT | _stream.type == 'Prometheus' and not _stream.id == 10 |
== | Equal to | _stream.type == 'Prometheus' |
~= | Not equal to | _stream.type ~ = 'Prometheus' |
> | More | _stream.id> 10 |
< | Less | _stream.id <10 |
>= | More or equal | _stream.id> = 10 |
<= | Less or equal | _stream.id <= 10 |
in (field, {args}) | Listed in | in (_stream.id,{10, 11, 15}) |
regexIsMatch (field, "(pattern)") | Regular Expression | regexIsMatch(source.@timestamp, "(\\d{4}-\\d{2}-\\d{2}T\\[0][0-9]:\\d{2}:\\d{2}\\.\\d+Z)") - returns true if the time in @timestamp is from 00 to 09 o'clock |
It is allowed to group parts of an expression using
()
.
Comparison operators are not case sensitive.
Objects of type
string
must be enclosed in single quotes.
Escaping occurs via
\
.
# Common fields
These fields can be used to filter any events:
Field | Type | Description |
---|---|---|
_stream.id | long | ID of the data stream that is the source of the event |
_stream.name | string | The name of the data stream that is the source of the event |
_labels.type | string | The type of the data stream that is the source of the event |
_aggregatedAt | DateTime | Time of receiving of the event |
source.@timestamp | DateTime | The time when the event was generated, as specified in the message |
# Prefilter templates
# SystemZabbixHost
_labels.type == 'Zabbix' AND _stream.id == <data stream ID> AND source.host.id == <Zabbix node ID>
# SystemZabbixTrigger
_labels.type == 'Zabbix' AND _stream.id == <data stream ID> AND source.trigger.id == '<Zabbix trigger ID>'
# SystemSCOM
_labels.type == 'SCOM' AND _stream.id == <data stream ID> and source.objectId == '<source object ID>'
To get the ID of a source object, use the command
Get-SCOMMonitoringObject -Name "<имя>"| select id
(see more (opens new window)).
# SystemPrometheusStandart
_labels.type == 'Prometheus' AND _stream.id == <data stream ID> AND source.labels.controller_pod == '<Controller pod>' AND source.labels.alertname == '<Alert name>'
# Rules
# Service variables
Variable | Class | Description |
---|---|---|
trigger | SyntheticTrigger | Synthetic trigger. |
_stream | Stream | The data stream that is the source of the event being processed. |
source | Any | The source that the raw event was received from. |
_labels | Any | A set of labels added to the event by the stream preprocessor. By default, it contains the type: string field - a designation of the stream type. |
# Service methods
Method | Parameters | Return type | Description |
---|---|---|---|
message: any | void | Print value of the method parameter | |
setTriggerStatus | newStatus: string ,labels: any (optional) | LuaResult<bool> | Change trigger status |
# Utility classes
# SyntheticTrigger
Field | Type | Description |
---|---|---|
id | number | Synthetic trigger Id |
name | string | Synthetic trigger name |
description | string | Synthetic trigger description |
status | string | The current status of the synthetic trigger |
# Stream
Field | Type | Description |
---|---|---|
id | number | Integration ID |
name | string | Integration name |
type | string | Integration type MOVED TO _LABELS.TYPE IN Acure 5.0 |
# Any
A table with an arbitrary set of fields.
# LuaResult
Field | Type | Description |
---|---|---|
data | type | The data returned by the method. Type can be any from the "Data Types" section. |
err | LuaCustomException | The field contains an object with a description of the error returned by the method. If there is no error, then the field will be in the nil status. |
# LuaCustomException
Field | Type | Description |
---|---|---|
message | string | Error message |
# Rule templates
# SystemZabbixTrigger
function convertTriggerStatus(value, priority)
if (value == 0) then
return 'Ok'
elseif (priority == 2) then
return 'Problem4'
elseif (priority == 3) then
return 'Problem3'
elseif (priority == 4) then
return 'Problem2'
elseif (priority == 5) then
return 'Problem1'
end
end
function generateLabels(newStatus)
return
{
eventName = source.host.name .. ': ' .. source.trigger.revealedDescription,
changeStatus = trigger.status .. ' → ' .. newStatus,
zTriggerName = source.trigger.revealedDescription,
zHostName = source.host.name,
zHostgroupName = source.group.name
}
end
local triggerStatus = convertTriggerStatus(source.trigger.value, source.trigger.priority)
if (triggerStatus ~= nil and trigger.status ~= triggerStatus) then
local labels = generateLabels(triggerStatus)
setTriggerStatus(triggerStatus, labels)
end
# SystemSCOM
function convertSeverity(value)
local severityEnum =
{
["Information"] = 0,
["Warning"] = 1,
["Error"] = 2
}
return severityEnum[value]
end
function convertPriority(value)
local priorityEnum =
{
["Low"] = 0,
["Medium"] = 1,
["High"] = 2
}
return priorityEnum[value]
end
function convertTriggerStatus(severity, priority)
local scomPriority = convertPriority(priority) * 3 + convertSeverity(severity) + 1
if (scomPriority == 2 or scomPriority == 3) then
return 'Problem4'
elseif (scomPriority == 4 or scomPriority == 5) then
return 'Problem3'
elseif (scomPriority == 6 or scomPriority == 7) then
return 'Problem2'
elseif (scomPriority == 8 or scomPriority == 9) then
return 'Problem1'
else
return 'Ok'
end
end
local triggerStatus = convertTriggerStatus(source.severity, source.priority)
if (triggerStatus ~= nil and trigger.status ~= triggerStatus) then
setTriggerStatus(triggerStatus)
end
# Examples of synthetic triggers
This section contains examples of some synthetic trigger implementations with highly specialized functions.
# nagios
Conversion of statuses 1-to-1.
state: Unknown
is ignored.An example of a prefilter for service monitoring:
connector.id == 1 AND source.hostName == 'test host' AND source.serviceDescription == 'test service' AND source.objecttypeId == 2
Example of a prefilter for host monitoring:
connector.id == 1 AND source.hostName == 'test host' AND source.objecttypeId == 1
function convertEventStatus(value) if (value == 0) then return 'Ok' elseif (value == 1) then return 'Problem1' elseif (value == 2) then return 'Problem2' end end local newStatus = convertEventStatus(source.state) if (trigger.status ~= newStatus and source.state ~= 3) then setTriggerStatus(newStatus) end
# prometheusUniversalWithGrouping
Universal trigger of Prometheus, suitable for a case when grouping is configured in the alertmanager
.
Remembers active problems and sets the highest priority.
-- Function for converting time to timestamp
function toTimeStamp(dateString)
local inYear, inMonth, inDay, inHour, inMinute, inSecond, inMsec, inZone =
string.match(dateString, '^(%d%d%d%d)-(%d%d)-(%d%d)T(%d%d):(%d%d):(%d%d)%.(%d-)([%+%-].-)$')
local zHours, zMinutes = string.match(inZone, '^(.-):(%d%d)$')
local returnTime = os.time({year=inYear, month=inMonth, day=inDay, hour=inHour, min=inMinute, sec=inSecond, isdst=false})
if zHours then
returnTime = returnTime - ((tonumber(zHours)*3600) + (tonumber(zMinutes)*60))
end
return returnTime
end
-- Function for setting trigger status by numeric value
function setTrigger(numstat)
if (numstat == 0) then
setTriggerStatus('Ok')
elseif (numstat == 1) then
setTriggerStatus('Problem4')
elseif (numstat == 2) then
setTriggerStatus('Problem3')
elseif (numstat == 3) then
setTriggerStatus('Problem2')
elseif (numstat == 4) then
setTriggerStatus('Problem1')
end
end
-- Function to convert event priority to numeric value
function convertEventSeverity(severity)
local eventSeverity =
{ ["disaster"] = 4, ["high"] = 3, ["warning"] = 2, ["info"] = 1 }
return eventSeverity[severity]
end
-- Function to convert SM trigger status to numeric value
function convertTriggerStatus(status)
local triggerStatus =
{ ["Ok"] = 0, ["Problem4"] = 1, ["Problem3"] = 2, ["Problem2"] = 3, ["Problem1"] = 4 }
return triggerStatus[status]
end
-- Function to search key by value in a table
function findEvent(table,element)
for k,v in pairs(table) do
if (deepcompare(json.decode(v), element)) then
return k
end
end
end
-- String splitting function
function split(s, delimiter)
result = {};
for match in (s..delimiter):gmatch("(.-)"..delimiter) do
table.insert(result, match);
end
return result;
end
-- Function to compare tables
function deepcompare(t1,t2,ignore_mt)
local ty1 = type(t1)
local ty2 = type(t2)
if ty1 ~= ty2 then return false end
if ty1 ~= 'table' and ty2 ~= 'table' then return t1 == t2 end
local mt = getmetatable(t1)
if not ignore_mt and mt and mt.__eq then return t1 == t2 end
for k1,v1 in pairs(t1) do
local v2 = t2[k1]
if v2 == nil or not deepcompare(v1,v2) then return false end
end
for k2,v2 in pairs(t2) do
local v1 = t1[k2]
if v1 == nil or not deepcompare(v1,v2) then return false end
end
return true
end
-- Calculating the numeric value of the trigger and of the received event
local oldSeverity = convertTriggerStatus(trigger.status)
local newSeverity = convertEventSeverity(source.labels.severity)
-- Change of status Ok -> Problem
if (trigger.status == 'Ok' and source.status == 'firing') then
setTrigger(newSeverity)
alerts = {json.encode({time=toTimeStamp(source.startsAt), alertname=source.labels.alertname, severity=source.labels.severity})}
_G["alerts"] = table.concat(alerts,";")
-- Change of status Problem -> Problem
elseif (trigger.status ~= 'Ok' and source.status == 'firing') then
if (newSeverity > oldSeverity) then
setTrigger(newSeverity)
end
alerts = split(_G["alerts"],";")
table.insert(alerts, json.encode({time=toTimeStamp(source.startsAt), alertname=source.labels.alertname, severity=source.labels.severity}))
_G["alerts"] = table.concat(alerts,";")
-- Change of status Problem -> Ok
elseif (trigger.status ~= 'Ok' and source.status == 'resolved') then
alerts = split(_G["alerts"],";")
local alertKey = findEvent(alerts,{time=toTimeStamp(source.startsAt), alertname=source.labels.alertname, severity=source.labels.severity})
if (alertKey ~= nil) then
table.remove(alerts,alertKey)
if (#alerts == 0) then
setTriggerStatus('Ok')
_G["alerts"] = ""
else
-- Search for maximum severity among active events
local newSeverity = convertEventSeverity(json.decode(alerts[1])['severity'])
for k,v in pairs(alerts) do
local vnewSeverity = convertEventSeverity(json.decode(v)['severity'])
if vnewSeverity > newSeverity then
newSeverity = vnewSeverity
end
end
-- Setting a trigger with maximum severity
setTrigger(newSeverity)
_G["alerts"] = table.concat(alerts,";")
end
end
end
# prometheusWithoutGrouping
Universal trigger of Prometheus. Suitable for a case when grouping is not configured in the alertmanager
.
Remembers active problems and sets the highest priority.
-- Function for converting time to timestamp
function toTimeStamp(dateString)
local inYear, inMonth, inDay, inHour, inMinute, inSecond, inMsec, inZone =
string.match(dateString, '^(%d%d%d%d)-(%d%d)-(%d%d)T(%d%d):(%d%d):(%d%d)%.(%d-)([%+%-].-)$')
local zHours, zMinutes = string.match(inZone, '^(.-):(%d%d)$')
local returnTime = os.time({year=inYear, month=inMonth, day=inDay, hour=inHour, min=inMinute, sec=inSecond, isdst=false})
if zHours then
returnTime = returnTime - ((tonumber(zHours)*3600) + (tonumber(zMinutes)*60))
end
return returnTime
end
-- Function for setting trigger status by numeric value
function setTrigger(numstat)
if (numstat == 0) then
setTriggerStatus('Ok')
elseif (numstat == 1) then
setTriggerStatus('Problem4')
elseif (numstat == 2) then
setTriggerStatus('Problem3')
elseif (numstat == 3) then
setTriggerStatus('Problem2')
elseif (numstat == 4) then
setTriggerStatus('Problem1')
end
end
-- Function to convert event priority to numeric value
function convertEventSeverity(severity)
local eventSeverity =
{
["disaster"] = 4,
["high"] = 3,
["warning"] = 2,
["info"] = 1
}
return eventSeverity[severity]
end
-- Function to convert trigger status to numeric value
function convertTriggerStatus(status)
local triggerStatus =
{
["Ok"] = 0,
["Problem4"] = 1,
["Problem3"] = 2,
["Problem2"] = 3,
["Problem1"] = 4
}
return triggerStatus[status]
end
-- Calculating the numeric value of the trigger and of the event
local oldSeverity = convertTriggerStatus(trigger.status)
local newSeverity = convertEventSeverity(source.labels.severity)
if (source.status == 'firing' and trigger.status == 'Ok') then
setTrigger(newSeverity)
_G["eventTime"] = toTimeStamp(source.startsAt)
_G["newStatus"] = 1
elseif (source.status == 'firing' and trigger.status ~= 'Ok') then
local newEventTime = toTimeStamp(source.startsAt)
print(source.startsAt)
if (_G["newStatus"] == 0) then
setTrigger(newSeverity)
_G["newStatus"] = 1
_G["eventTime"] = newEventTime
else
if newSeverity > oldSeverity then
setTrigger(newSeverity)
_G["eventTime"] = newEventTime
elseif (newSeverity == oldSeverity and _G["eventTime"] < newEventTime) then
_G["eventTime"] = toTimeStamp(source.startsAt)
end
end
elseif (source.status == 'resolved' and trigger.status ~= 'Ok') then
if (toTimeStamp(source.startsAt) == _G["eventTime"] and newSeverity == oldSeverity) then
if (_G["newStatus"] == 0) then
setTrigger(0)
_G["newStatus"] = 0
else
_G["newStatus"] = 0
end
end
end
# SystemZabbixTrigger-5
Standard Zabbix trigger template, respecting the status of information
.
function convertTriggerStatus(value, priority)
if (value == 0) then
return 'Ok'
elseif (priority == 1) then
return 'Problem4'
elseif (priority == 2) then
return 'Problem4'
elseif (priority == 3) then
return 'Problem3'
elseif (priority == 4) then
return 'Problem2'
elseif (priority == 5) then
return 'Problem1'
end
end
function generateLabels(newStatus)
return
{
eventName = source.host.name .. ': ' .. source.trigger.revealedDescription,
changeStatus = trigger.status .. ' → ' .. newStatus,
zTriggerName = source.trigger.revealedDescription,
zHostName = source.host.name,
zHostgroupName = source.group.name
}
end
local triggerStatus = convertTriggerStatus(source.trigger.value, source.trigger.priority)
if (triggerStatus ~= nil and trigger.status ~= triggerStatus) then
local labels = generateLabels(triggerStatus)
setTriggerStatus(triggerStatus, labels)
end
# vrops
A trigger template for handling events from VMware vRealize Operations via an intermediate shim.
Prefilter example: _stream.id = 2 and source.resourceName = 'test-server'
-- Priority conversion function (returns alphabetic and numeric version)
function convertSeverity(severity)
if (severity == "ALERT_CRITICALITY_LEVEL_INFO" or severity == "Problem4") then
return {char="Problem4", num=4}
elseif (severity == "ALERT_CRITICALITY_LEVEL_WARNING" or severity == "Problem3") then
return {char="Problem3", num=3}
elseif (severity == "ALERT_CRITICALITY_LEVEL_IMMEDIATE" or severity == "Problem2") then
return {char="Problem2", num=2}
elseif (severity == "ALERT_CRITICALITY_LEVEL_CRITICAL" or severity == "Problem1") then
return {char="Problem1", num=1}
else
return {char="Ok", num=5}
end
end
-- Label setting function
function generateLabels(alert)
return {eventName = alert.AlertName}
end
local priority = convertSeverity(source.criticality)
local labels = generateLabels(source)
-- OK -> Problem
if (source.status == 'ACTIVE' and trigger.status == 'Ok') then
setTriggerStatus(priority.char, labels)
local problems = {}
problems[source.alertId] = {priority = priority, labels = labels}
_G["problems"] = json.encode(problems)
_G["active"] = source.alertId
-- Problem -> Problem
elseif (source.status == 'ACTIVE' and trigger.status ~= 'Ok') then
local oldPriority = convertSeverity(trigger.status)
if (priority.num < oldPriority.num) then
setTriggerStatus(priority.char, labels)
_G["active"] = source.alertId
end
local problems = json.decode(_G["problems"])
problems[source.alertId] = {priority = priority, labels = labels}
_G["problems"] = json.encode(problems)
-- Problem -> Ok
elseif (source.status == 'CANCELED' and trigger.status ~= 'Ok') then
local problems = json.decode(_G["problems"])
problems[source.alertId] = nil
if (source.alertId == _G["active"]) then
local candidate={priority={num=5, char="Ok"}}
for k,v in pairs(problems) do
if (v.priority.num < candidate.priority.num) then
candidate = v
_G["active"] = k
end
end
setTriggerStatus(candidate.priority.char, candidate.labels)
end
_G["problems"] = json.encode(problems)
end
# zabbixAccumulateWithDelay
- Sets the highest priority of the problem among the triggers that fit into it.
- Remembers active problems.
- As problems are closed, the highest priority among still active problems is set.
- Closes only after the
timeout
has expired, after the last problem was closed.
-- Function for converting event priority to trigger status
function convertTriggerStatus(value, priority)
if (value == 0) then
return 'Ok'
elseif (priority == 2) then
return 'Problem4'
elseif (priority == 3) then
return 'Problem3'
elseif (priority == 4) then
return 'Problem2'
elseif (priority == 5) then
return 'Problem1'
end
end
-- Function for searching key by eventId
function findEvent(table,element)
for k,v in pairs(table) do
if (json.decode(v)['id'] == element) then
return k
end
end
end
-- Function to convert trigger status to event priority
function convertTriggerPriority(value)
if (value == 'Problem1') then
return 5
elseif (value == 'Problem2') then
return 4
elseif (value == 'Problem3') then
return 3
else
return 2
end
end
function split(s, delimiter)
result = {};
for match in (s..delimiter):gmatch("(.-)"..delimiter) do
table.insert(result, match);
end
return result;
end
-- Setting a cleanup timeout
local timeout = 300
-- Checking the start of the scheduler calculation and the conditions for closing
if (isScheduled == true) then
if (_G["clear"] == true and (os.time()-_G["clearTime"]) >= timeout and trigger.status ~= 'Ok') then
print("clear")
setTriggerStatus('Ok')
end
else
-- Calculating a new trigger value
local newSeverity = convertTriggerStatus(source.trigger.value, source.trigger.priority)
if (trigger.status == 'Ok' and newSeverity ~= 'Ok') then
setTriggerStatus(newSeverity)
triggers = {json.encode({id = source.trigger.id, priority = source.trigger.priority})}
_G["triggers"] = table.concat(triggers,";")
_G["clear"] = false
elseif (trigger.status ~= 'Ok' and newSeverity ~= 'Ok') then
if (convertTriggerPriority(trigger.status) < source.trigger.priority) then
setTriggerStatus(newSeverity)
end
if (#_G["triggers"] > 0) then
triggers = split(_G["triggers"],";")
table.insert(triggers, json.encode({id = source.trigger.id, priority = source.trigger.priority }))
else
triggers = {json.encode({id = source.trigger.id, priority = source.trigger.priority})}
end
_G["triggers"] = table.concat(triggers,";")
_G["clear"] = false
elseif (trigger.status ~= 'Ok' and newSeverity == 'Ok') then
triggers = split(_G["triggers"],";")
local triggerKey = findEvent(triggers,source.trigger.id)
if (triggerKey ~= nil) then
table.remove(triggers, triggerKey)
if (#triggers == 0) then
_G["clear"] = true
_G["clearTime"] = os.time()
_G["triggers"] = ""
scheduler:executeAfter(timeout)
else
if (convertTriggerPriority(trigger.status) == source.trigger.priority) then
local newPriority = json.decode(triggers[1])['priority']
for k,v in pairs(triggers) do
if (json.decode(v)['priority'] > newPriority) then
newPriority = json.decode(v)['priority']
end
end
setTriggerStatus(convertTriggerStatus(1,newPriority))
end
_G["triggers"] = table.concat(triggers,";")
end
end
end
end
# zabbixAccumulateWithDelayPeakSeverity
- Sets the highest priority of the problem among the triggers that fit into it.
- Remembers active problems.
- As the problems are closed, the maximum of the problem priorities is set and does not decrease.
- Closes only after the
timeout
has expired, after the last problem was closed.
-- Function for converting event priority to trigger status
function convertTriggerStatus(value, priority)
if (value == 0) then
return 'Ok'
elseif (priority == 2) then
return 'Problem4'
elseif (priority == 3) then
return 'Problem3'
elseif (priority == 4) then
return 'Problem2'
elseif (priority == 5) then
return 'Problem1'
end
end
-- Function for searching key by eventId
function findEvent(table,element)
for k,v in pairs(table) do
if (v == element) then
return k
end
end
end
-- Function to convert trigger status to event priority
function convertTriggerPriority(value)
if (value == 'Problem1') then
return 5
elseif (value == 'Problem2') then
return 4
elseif (value == 'Problem3') then
return 3
else
return 2
end
end
function split(s, delimiter)
result = {};
for match in (s..delimiter):gmatch("(.-)"..delimiter) do
table.insert(result, match);
end
return result;
end
-- Setting a cleanup timeout
local timeout = 900
-- Checking the start of the scheduler calculation and the conditions for closing
if (isScheduled == true) then
if (_G["clear"] == true and (os.time()-_G["clearTime"]) >= timeout and trigger.status ~= 'Ok') then
setTriggerStatus('Ok')
end
else
-- Calculating a new trigger value
local newSeverity = convertTriggerStatus(source.trigger.value, source.trigger.priority)
if (trigger.status == 'Ok' and newSeverity ~= 'Ok') then
setTriggerStatus(newSeverity)
_G["triggers"] = table.concat({source.trigger.id},";")
_G["clear"] = false
elseif (trigger.status ~= 'Ok' and newSeverity ~= 'Ok') then
if (convertTriggerPriority(trigger.status) < source.trigger.priority) then
setTriggerStatus(newSeverity)
end
if (#_G["triggers"] > 0) then
triggers = split(_G["triggers"],";")
table.insert(triggers, source.trigger.id)
else
triggers = {source.trigger.id}
end
_G["triggers"] = table.concat(triggers,";")
_G["clear"] = false
elseif (trigger.status ~= 'Ok' and newSeverity == 'Ok') then
triggers = split(_G["triggers"],";")
local triggerKey = findEvent(triggers,source.trigger.id)
if (triggerKey ~= nil) then
table.remove(triggers, triggerKey)
if (#triggers == 0) then
_G["clear"] = true
_G["clearTime"] = os.time()
_G["triggers"] = ""
scheduler:executeAfter(timeout)
else
_G["triggers"] = table.concat(triggers,";")
end
end
end
end
# zabbixByWeight
- Sets its status based on the sum of the weights of the problems that fit into it.
- The weight of the problem is determined according to the priority (1-5).
- Threshholds are set in the setTriggerStatusByWeight function.
-- Function for calculating and setting the trigger status
function setTriggerStatusByWeight(weight)
if (weight == 0) then
setTriggerStatus('Ok')
elseif (weight > 0 and weight <= 5) then
setTriggerStatus('Problem4')
elseif (weight > 5 and weight <= 10) then
setTriggerStatus('Problem3')
elseif (weight > 10 and weight <= 15) then
setTriggerStatus('Problem2')
elseif (weight > 15) then
setTriggerStatus('Problem1')
end
_G['weight'] = weight
end
-- Initialization of the global variable "Weights" of the trigger
if (trigger.status == 'Ok') then
_G['weight']=0
end
-- Checking the priority of the problem is greater than 1 (Warning or higher)
if (source.trigger.priority > 1) then
if (source.trigger.value == 1) then
setTriggerStatusByWeight(_G['weight']+source.trigger.priority)
else
if (source.trigger.priority >= _G['weight']) then
setTriggerStatusByWeight(0)
else
setTriggerStatusByWeight(_G['weight']-source.trigger.priority)
end
end
end