Condition Language Functions
Overview
The correlator dialect provides about a hundred functions. Most of them match standard SML in both name and behavior. The remaining functions either exist only in the correlator or behave differently from the SML functions of the same name.
Functions Identical to Standard SML
Conditions and Comparison
| Function | Description |
|---|---|
case | returns the value of the first true condition in a list of pairs |
validate | the inverse of case: returns the value of the first false condition |
if | returns one of two values depending on a condition |
coalesce | returns the first non-empty value from those listed |
nullif | returns null if two values are equal, otherwise the first of them |
in | checks whether a field value belongs to the listed set |
like | matches a value against an SQL-style pattern (%, _) |
match | matches a value against a regular expression |
cidrmatch | checks whether an IP address belongs to a subnet |
Value Type Checks
| Function | Description |
|---|---|
isnull | the value is absent |
isnotnull | the value is present |
isstr | the value is a string |
isnum | the value is a number |
isint | the value is an integer |
isbool | the value is Boolean |
typeof | returns the name of the value type |
Type Conversion
| Function | Description |
|---|---|
tonumber | converts a value to a number; the second argument is a radix from 2 to 36 |
tobool | converts a value to Boolean |
Text
| Function | Description |
|---|---|
len | string length; for a multivalue field, the number of elements |
lower | converts a string to lowercase |
upper | converts a string to uppercase |
trim | removes the specified characters from both ends of a string; without a second argument, removes whitespace |
ltrim | the same on the left |
rtrim | the same on the right |
replace | replaces occurrences of a pattern; capture groups $1, $2, ${name} are available in the replacement string |
urlencode | encodes a string for use in a URL |
urldecode | the reverse conversion |
Mathematics
| Function | Description |
|---|---|
abs | absolute value |
ceil | rounds up |
floor | rounds down |
round | rounds to the specified number of digits; by default, to an integer |
exp | exponent |
ln | natural logarithm |
log | logarithm to the specified base; with one argument, base 10 |
pow | exponentiation |
sqrt | square root |
pi | the number pi |
max | the largest of the listed values or array elements |
min | the smallest of them |
Multivalue Fields
| Function | Description |
|---|---|
mvcount | number of elements |
mvindex | element at an index; the third argument sets the end of a range |
mvfind | index of the first element matching a regular expression |
mvdedup | removes duplicate elements |
mvsort | sorts elements |
mvappend | combines values into a single multivalue |
mvjoin | joins elements into a string using a delimiter |
mvrange | builds a numeric series |
mvzip | pairwise combines the elements of two fields |
split | splits a string by a delimiter |
Hashing
| Function | Description |
|---|---|
md5 | MD5 hash |
sha1 | SHA-1 hash |
sha256 | SHA-256 hash |
sha512 | SHA-512 hash |
Hashes are returned in lowercase.
Time
| Function | Description |
|---|---|
now | current time in Unix format |
time | the same: time is a synonym for now |
The correlator works with time in whole Unix seconds and in the UTC zone. If a time function is not given an explicit time zone, the calculation is performed in UTC.
Functions That Behave Differently
The functions below exist in both SML and the correlator but behave differently.
strftime
Formats a Unix time. Unlike SML, the pattern is not written in Joda Time format but as the reference date Mon Jan 2 15:04:05 MST 2006: each pattern element is the corresponding part of that reference date.
Syntax
strftime(<time>, <pattern>)
| Pattern element | Meaning | Pattern element | Meaning |
|---|---|---|---|
2006 | four-digit year | 15 | hours in 24-hour format |
01 | two-digit month | 04 | minutes |
02 | two-digit day | 05 | seconds |
Jan | abbreviated month | Z07:00 | zone offset |
Examples
strftime(@timestamp, "2006-01-02") == "2026-08-06"
An empty pattern or a non-numeric time yields an empty string.
strptime
Parses a time string and returns a Unix time. The pattern is written the same way as in strftime
Syntax
strptime(<string>, <pattern>)
Examples
now() - strptime(start_time, "2006-01-02T15:04:05Z07:00") > 300
If the string or the pattern cannot produce a moment in time, null is returned.
relative_time
Shifts a moment in time and rounds it down to a period boundary. It differs from SML in three ways: the offset is written as a quoted string, the shift may be followed by rounding through @, and there is a third optional argument, the time zone whose boundaries rounding uses.
Syntax
relative_time(<time>, "<offset>" [, <time zone>])
The offset has the form [(+|-)<integer><unit>][@<unit>], where the unit is one of s, m, h, d, w, M.
| Part | Purpose |
|---|---|
(+|-)<integer><unit> | the shift; the sign is required |
@<unit> | rounds down to a period boundary |
Unit case matters: m means minutes and M means months. The shift is applied first and the rounding second.
Examples
relative_time(@timestamp, "-1h")
relative_time(@timestamp, "@d")
relative_time(@timestamp, "-1d@d", "Europe/Moscow")
The first expression yields the moment one hour earlier, the second the start of the day in UTC, and the third the start of yesterday in Moscow time. Without the third argument, day, week, and month boundaries are calculated in UTC.
to_timezone
Returns a string containing the local time of the specified zone rather than a shifted Unix time as in SML. The time zone is required.
Syntax
to_timezone(<time>, <time zone>)
Examples
to_timezone(@timestamp, "Europe/Moscow") != nil
from_timezone
The reverse operation: it reads a string containing the local time of the specified zone and returns a Unix time. In SML this function takes a Unix time rather than a string.
Syntax
from_timezone(<local time string>, <time zone>)
Examples
from_timezone("2026-08-03 17:37:12", "Europe/Moscow")
A string that already carries its own zone offset is rejected; otherwise there would be two sources of the zone. An unparsable string or an unknown zone yields null.
tostring
Converts a value to a string. The additional HEX, COMMAS, DURATION, BYTES, and QUANTITY formats available in SML are not supported: the function takes exactly one argument.
Syntax
tostring(<value>)
Examples
tostring(event.code) == "4625"
substr
Extracts a substring. One-based numbering and a negative start counted from the end of the string work as in SML, but the second numeric argument is a length, not an end position.
Syntax
substr(<value>, <start> [, <length>])
Examples
substr(user.name, -4, 4) == "base"
substr(host.name, 1, 3) == "web"
A start of 0 is invalid in one-based numbering and yields an empty string, as does a start outside the string. The function works on characters rather than bytes, so multi-byte text is never cut mid-character.
For zero-based numbering, the dialect provides the separate substring function.
Correlator Functions
Accessing the Event and the Context
exist
Checks whether the event contains a field at the specified path. It differs from isnotnull in that it reports the presence of the field itself rather than whether its value is meaningful.
exist(<field path>)
not exist(process.name)
exist("user.name") or exist(process.parent.name)
source
Checks whether the event came from a source whose alias matches the pattern. The pattern may contain the * wildcard, and matching is case-insensitive.
source(<alias pattern>)
source("winlog*") and event.code == "4625"
ctx
Returns the value of a field saved by an imperative rule stage. It works only for stages with the Add to Context toggle enabled. See Imperative Rules.
ctx(<stage>, <field>)
Both arguments may be written either without quotes or in double quotes; quotes are needed if the name contains a space or other characters outside the usual set.
ctx(stage1, user.name) == "admin"
ctx("stage-1", "user@corp.local") != ""
ctx(stage_a, destination.host.name) == ctx(stage_b, host.name)
Active Lists
alcontains
Checks whether the active list contains a record whose specified field equals the specified value. Several field and value pairs may be given, in which case the record must match all of them.
alcontains(<list>, <field> as <value> [, <field> as <value>]...)
alcontains(ti_ip_blacklist, destination.ip as source.address)
alcontains(geo, ip as source.ip, country as source.geo.country_iso_code)
alget
Finds a record in an active list by value and returns the value of one of its fields.
alget(<list>, <value>, <field>)
alget(known_hosts, host.name, status) == "trusted"
alget(known_hosts, lower(user.name), 'user name') != nil
String Comparison and Parsing
contains
Checks for a substring, case-sensitively. For a multivalue field, it reports a match if the substring is found in at least one element.
contains(<value>, <substring>)
contains(process.command_line, "-enc")
startswith
Checks whether a value starts with the specified substring, case-sensitively.
startswith(<value>, <prefix>)
startswith(file.path, "C:\\Windows\\Temp")
endswith
Checks whether a value ends with the specified substring, case-sensitively.
endswith(<value>, <suffix>)
endswith(lower(file.name), ".ps1")
contains, startswith, and endswith are always case-sensitive. To compare without regard to case, wrap both sides in lower.
regex
Checks whether the value contains a match for a regular expression.
regex(<value>, <regular expression>)
regex(process.command_line, "(?i)powershell\\s+-enc")
extract
Returns the text of the first match of a regular expression. Without a third argument, the whole match is returned; with it, the contents of the named group (?P<name>...).
extract(<value>, <regular expression> [, <group name>])
extract(url.original, "session_id=(?P<sid>[a-z0-9]+)", "sid") != ""
If the expression is empty or invalid, there is no match, or the group captured nothing, an empty string is returned.
indexof
Returns the position of the first occurrence of a substring, or -1 if there is none.
indexof(<value>, <substring>)
indexof(process.command_line, "--password") >= 0
substring
Extracts a substring using zero-based numbering; the second numeric argument is a length. Values outside the string bounds are not an error: they are clamped to valid ones.
substring(<value>, <start> [, <length>])
substring(host.name, 0, 3) == "web"
String Similarity and Entropy
levenshtein
Returns the edit distance between two strings: the number of character insertions, deletions, and substitutions. Strings longer than 256 characters are truncated.
levenshtein(<value>, <value>)
levenshtein(lower(user.name), "administrator") <= 2
If both strings are empty - for example, both fields are absent from the event - null is returned rather than 0: there is nothing to compare.
similarity
Returns a normalized similarity measure from 0 to 1, where 1 means an exact match.
similarity(<value>, <value>)
similarity(dns.question.name, "microsoft.com") > 0.85
Like levenshtein, it returns null when both strings are empty.
entropy
Returns the Shannon entropy of a string in bits per character, roughly from 0 to 8. High entropy is characteristic of random and encoded strings such as algorithmically generated domains and encoded payloads.
entropy(<value>)
entropy(dns.question.name) > 3.5 and len(dns.question.name) > 12
Entropy depends on string length, so short values produce inflated results. Use it together with a length check. An empty value yields null rather than 0, because 0 is the legitimate entropy of a string made of one repeated character.
Multivalue Fields
mvcontains
Checks whether a multivalue field contains an element that is exactly equal to the specified value. Unlike contains, it looks for a whole-element match rather than a substring.
mvcontains(<multivalue field>, <value>)
mvcontains(host.ip, "10.0.0.1")
Type Conversion
tofloat
Converts a value to a floating-point number. A value that does not parse as a number, as well as infinity and not-a-number, yields null.
tofloat(<value>)
round(tofloat(risk.score)) >= 10
Encoding and Decoding
| Function | Syntax | Description |
|---|---|---|
base64encode | base64encode(<value>) | encodes a value in base64 |
base64decode | base64decode(<value>) | decodes base64; both the standard and URL-safe alphabets are recognized, with and without padding |
hexencode | hexencode(<value>) | encodes a value in hexadecimal |
hexdecode | hexdecode(<value>) | decodes a hexadecimal string |
contains(lower(base64decode(process.args)), "invoke-expression")
If the value cannot be decoded, an empty string is returned.
Network Addresses
| Function | Syntax | Description |
|---|---|---|
isip | isip(<value>) | the value is a valid IPv4 or IPv6 address |
isipv4 | isipv4(<value>) | the value is a valid IPv4 address |
isipv6 | isipv6(<value>) | the value is a valid IPv6 address |
isprivateip | isprivateip(<value>) | the address is private, loopback, or link-local: RFC 1918, ULA, 127.0.0.0/8, ::1, 169.254.0.0/16, fe80::/10 |
ispublicip | ispublicip(<value>) | the address is globally routable |
cidr_contains | cidr_contains(<subnet>, <address>) | the address belongs to the subnet; a full synonym of cidrmatch |
subnet | subnet(<address>, <prefix length>) | returns the subnet of the specified length that the address belongs to |
iptonumber | iptonumber(<address>) | returns the numeric value of an IPv4 address for range comparisons |
isprivateip(source.address) and cidr_contains("10.0.0.0/8", source.address)
subnet(source.ip, 24) == "10.0.5.0/24"
Time
timediff
Returns the difference between two moments in time, in seconds.
timediff(<time>, <time>)
timediff(event.end, event.start) > 3600
age
Returns how many seconds have passed from the specified moment until now. Equivalent to now() - <time>.
age(<time>)
age(user.last_password_change) > 7776000
hourofday
Returns the hour of the day from 0 to 23. Without a second argument, the calculation is performed in UTC.
hourofday(<time> [, <time zone>])
hourofday(@timestamp, "Europe/Moscow") < 6
dayofweek
Returns the day of the week as a number, where 0 is Sunday and 6 is Saturday. Without a second argument, the calculation is performed in UTC.
dayofweek(<time> [, <time zone>])
dayofweek(@timestamp, "Europe/Moscow") == 1
isweekend
Checks whether a moment falls on a Saturday or Sunday.
isweekend(<time> [, <time zone>])
isweekend(@timestamp, "Europe/Moscow") and event.code == "4624"
inbusinesshours
Checks whether the hour of a moment falls within the interval from <start hour> inclusive to <end hour> exclusive.
inbusinesshours(<time>, <start hour>, <end hour> [, <time zone>])
not inbusinesshours(@timestamp, 9, 19, "Europe/Moscow")
All four functions take a time zone as an IANA database name, for example Europe/Moscow. If a zone is specified and cannot be resolved, the result is null for hourofday and dayofweek and false for isweekend and inbusinesshours. Omitting the argument means UTC and is not an error.
Collections
join
Joins the elements of a multivalue field into a string using a delimiter. A single value is treated as a one-element collection.
join(<multivalue field>, <delimiter>)
join(user.roles, ",") != ""
sum
Adds the numeric elements of a collection. Elements that are not numbers are skipped; if there is nothing to add, null is returned.
sum(<collection>)
sum(scores) / len(scores) > 5