Перейти к основному содержимому
Версия: 4.6.X

Справочник CEL-функций

Все модули нормализации (deny, if, assign) используют Common Expression Language (CEL) для написания выражений. В данном справочнике перечислены все функции, доступные в CEL-окружении KOMRAD.


Доступ к полям события

Переменная event предоставляет доступ ко всем полям текущего события.

ФункцияВозвратОписание
event.vars("field")dynПолучить значение поля. Возвращает null, если поле отсутствует
event.as_string("field")stringПолучить значение поля как строку. Возвращает "", если поле отсутствует
event["field"]dynПрямой доступ к полю (вызывает ошибку, если поле отсутствует)
event.RawstringПрямой доступ к базовому полю (аналогично для других базовых полей)

Базовые поля события

К следующим полям можно обращаться напрямую через event.<поле>:

ПолеТипОписание
RawstringИсходный текст события
ProducerstringИдентификатор источника
PluginIDslistСписок ID плагинов
AssetIPslistIP связанных активов
KeystringКлюч события
CountintЧисло агрегированных событий
FwdIPstringIP-адрес отправителя
FwdPortintПорт отправителя
CollectorIDstringID коллектора
CollectorTypestringТип коллектора
SetupIDstringID настройки
AggregationNamestringМетка агрегации
CTimetimestampВремя создания
WTimetimestampВремя записи
GenerationTimetimestampВремя генерации
SLuintМетка безопасности
TenantIDuintID тенанта
CustommapКарта пользовательских полей (ECS.*)

Примеры

# Безопасный доступ с проверкой на null
event.vars("ECS.Client.IP") != null ? event.as_string("ECS.Client.IP") : "unknown"

# Прямой доступ к базовым полям
event.Raw.startsWith("system,info")
event.FwdIP.in_cidr("10.0.0.0/8")

Работа со строками

Проверки и сравнения

ФункцияВозвратОписание
s.contains_substr(sub)boolСодержит ли строка подстроку
s.contains_any(chars)boolСодержит ли строка любой символ из набора
s.has_prefix(prefix)boolНачинается ли строка с префикса
s.has_suffix(suffix)boolЗаканчивается ли строка суффиксом
s.startsWith(prefix)boolНачинается ли строка с префикса (стандарт CEL)
s.endsWith(suffix)boolЗаканчивается ли строка суффиксом (стандарт CEL)
s.equal_fold(other)boolРегистронезависимое сравнение
s.compare(other)intЛексикографическое сравнение (-1, 0, 1)

Поиск

ФункцияВозвратОписание
s.index(sub)intИндекс первого вхождения подстроки (-1 если нет)
s.last_index(sub)intИндекс последнего вхождения подстроки
s.index_any(chars)intИндекс первого символа из набора
s.last_index_any(chars)intИндекс последнего символа из набора
s.count(sub)intКоличество неперекрывающихся вхождений

Преобразование

ФункцияВозвратОписание
s.to_lower()stringПреобразование в нижний регистр
s.to_upper()stringПреобразование в верхний регистр
s.to_title()stringПреобразование в Title Case
s.replace_all(old, new)stringЗамена всех вхождений
s.repeat(n)stringПовторить строку n раз
s.canonical_mime_header_key()stringКанонический MIME-заголовок

Разделение и объединение

ФункцияВозвратОписание
s.split(sep)list(string)Разделить строку по разделителю (ext.Strings)
s.split_n(sep, n)list(string)Разделить с максимальным числом частей
s.split_after(sep)list(string)Разделить после каждого вхождения разделителя
s.split_after_n(sep, n)list(string)Разделить после разделителя с лимитом
s.fields()list(string)Разделить по пробельным символам
list.join(sep)stringОбъединить список строк через разделитель (ext.Strings)

Обрезка

ФункцияВозвратОписание
s.trim(chars)stringУдалить символы с обеих сторон
s.trim_left(chars)stringУдалить символы слева
s.trim_right(chars)stringУдалить символы справа
s.trim_space()stringУдалить пробельные символы с обеих сторон
s.trim_prefix(prefix)stringУдалить префикс
s.trim_suffix(suffix)stringУдалить суффикс

Извлечение подстрок

ФункцияВозвратОписание
s.substring(start, end)stringПодстрока по позициям Unicode code points [start:end)
s.charAt(i)stringСимвол по индексу (ext.Strings)
s.indexOf(sub)intИндекс подстроки (ext.Strings)
s.lastIndexOf(sub)intПоследний индекс подстроки (ext.Strings)

Форматирование

ФункцияВозвратОписание
format.sprintf(args)stringФорматирование строки (синтаксис Go fmt.Sprintf)
sprintf(format, args)stringФорматирование строки (свободная функция)

Примеры

# Извлечение домена из email
event.as_string("ECS.User.Email").split("@")[1]

# Проверка формата
event.Raw.has_prefix("system,") && event.Raw.has_suffix("via ssh")

# Замена и преобразование
event.as_string("ECS.Host.Name").to_lower().replace_all(" ", "_")

Регулярные выражения

Регулярные выражения используют синтаксис RE2. Паттерны, определённые в блоке regex: конфигурации, предварительно компилируются и доступны по имени.

ФункцияВозвратОписание
s.re_match(pattern)boolСовпадает ли строка с паттерном
s.re_find(pattern)stringПервое совпадение
s.re_find_all(pattern)list(string)Все совпадения
s.re_find_submatch(pattern)list(string)Группы захвата первого совпадения
s.re_find_all_submatch(pattern)list(list(string))Группы захвата всех совпадений
s.re_replace_all(pattern, repl)stringЗамена всех совпадений (поддержка $1, ${name})

Все функции также работают с типом bytes.

Примеры

# Проверка формата события
event.Raw.re_match('^system,info,account user \\w+ logged in')

# Извлечение групп захвата
event.Raw.re_find_submatch('^user (\\w+) from (\\S+)')[1] # имя пользователя
event.Raw.re_find_submatch('^user (\\w+) from (\\S+)')[2] # адрес

# Безопасное извлечение с проверкой размера
size(event.Raw.re_find_submatch('pattern (\\w+)')) > 1
? event.Raw.re_find_submatch('pattern (\\w+)')[1]
: ''

# Замена
event.as_string("Raw").re_replace_all('\\d+', 'N')

Хеширование и кодирование

Хеш-функции

ФункцияВозвратОписание
s.md5() / md5(s)bytesMD5 хеш
s.sha1() / sha1(s)bytesSHA-1 хеш
s.sha256() / sha256(s)bytesSHA-256 хеш
s.hmac(algo, key)bytesHMAC (algo: "sha1" или "sha256", key: bytes)

Кодирование

ФункцияВозвратОписание
s.base64() / base64(s)stringBase64 кодирование (стандартное)
s.base64_decode()bytesBase64 декодирование
s.base64_raw() / base64_raw(s)stringBase64 без дополнения (raw)
s.base64_raw_decode()bytesДекодирование raw Base64
s.hex() / hex(s)stringШестнадцатеричное кодирование
s.hex_decode() / hex_decode(s)bytesДекодирование hex-строки

Генерация

ФункцияВозвратОписание
uuid()stringГенерация случайного UUID v4

Все хеш-функции работают как со строками, так и с байтами.

Примеры

# SHA-256 хеш события в hex
event.Raw.sha256().hex()

# Base64 кодирование
event.as_string("ECS.Message").base64()

# HMAC-SHA256
event.Raw.hmac("sha256", b"secret_key").hex()

# Генерация уникального идентификатора
uuid()

Работа с JSON

ФункцияВозвратОписание
v.encode_json() / encode_json(v)stringКодировать значение в JSON-строку
s.decode_json() / decode_json(s)dynДекодировать JSON-строку в объект
s.decode_json_string_numbers()dynДекодировать JSON, числа как строки
s.decode_json_stream()list(dyn)Декодировать поток JSON-объектов (NDJSON)
s.decode_json_stream_string_numbers()list(dyn)Декодировать поток JSON, числа как строки
s.jsonpath_has(path)boolПроверить наличие JSONPath в JSON-строке
s.jsonpath_get(path)dynИзвлечь значение по JSONPath из JSON-строки

Функции decode_json и decode_json_stream работают как со строками, так и с байтами.

Примеры

# Парсинг JSON из сырого события
event.Raw.decode_json()

# Извлечение по JSONPath
event.as_string("Raw").jsonpath_get("$.user.id")

# Проверка наличия поля
event.as_string("Raw").jsonpath_has("$.error")

# Кодирование в JSON
{"key": "value"}.encode_json()

Работа с XML

ФункцияВозвратОписание
s.decode_xml() / decode_xml(s)dynДекодировать XML в map (без схемы)
s.decode_xml(schema)dynДекодировать XML с использованием именованной XSD-схемы

XSD-схемы задаются в конфигурации модуля через поле xml-xsd:

processors:
- module: assign
xml-xsd:
order: |
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
...
</xs:schema>
assign:
- target: ECS.Data
cel: 'event.Raw.decode_xml("order")'

Работа со временем

Функции

ФункцияВозвратОписание
now()timestampТекущее UTC-время в момент вызова
ts.format(layout)stringФорматировать timestamp по шаблону Go time layout
s.parse_time(layout)timestampПарсинг строки во время по шаблону
s.parse_time(layouts)timestampПарсинг строки, попробовать несколько шаблонов
ts.round(duration)timestampОкруглить время до ближайшего кратного duration
ts.truncate(duration)timestampОтсечь время до кратного duration
d.round(duration)durationОкруглить длительность
d.truncate(duration)durationОтсечь длительность

Глобальные переменные

ПеременнаяТипОписание
nowtimestampВремя начала вычисления (вычисляется один раз)
time_layoutmapКарта именованных шаблонов времени

Шаблоны времени (time_layout)

КлючЗначениеОписание
time_layout.RFC3339"2006-01-02T15:04:05Z07:00"ISO 8601
time_layout.RFC3339Nano"2006-01-02T15:04:05.999999999Z07:00"С наносекундами
time_layout.DateTime"2006-01-02 15:04:05"Дата и время
time_layout.DateOnly"2006-01-02"Только дата
time_layout.TimeOnly"15:04:05"Только время
time_layout.RFC1123"Mon, 02 Jan 2006 15:04:05 MST"RFC 1123
time_layout.RFC1123Z"Mon, 02 Jan 2006 15:04:05 -0700"RFC 1123 с числовой зоной
time_layout.RFC822"02 Jan 06 15:04 MST"RFC 822
time_layout.RFC822Z"02 Jan 06 15:04 -0700"RFC 822 с числовой зоной
time_layout.RFC850"Monday, 02-Jan-06 15:04:05 MST"RFC 850
time_layout.ANSIC"Mon Jan _2 15:04:05 2006"ANSI C
time_layout.UnixDate"Mon Jan _2 15:04:05 MST 2006"Unix
time_layout.RubyDate"Mon Jan 02 15:04:05 -0700 2006"Ruby
time_layout.Kitchen"3:04PM"Время кухонных часов
time_layout.Stamp"Jan _2 15:04:05"Syslog-формат
time_layout.StampMilli"Jan _2 15:04:05.000"С миллисекундами
time_layout.StampMicro"Jan _2 15:04:05.000000"С микросекундами
time_layout.StampNano"Jan _2 15:04:05.000000000"С наносекундами
time_layout.HTTP"Mon, 02 Jan 2006 15:04:05 GMT"HTTP-дата
time_layout.Layout"01/02 03:04:05PM '06 -0700"Эталонный шаблон Go

Примеры

# Текущее время в формате RFC3339
now().format(time_layout.RFC3339)

# Парсинг времени из строки
event.as_string("ECS.Timestamp").parse_time(time_layout.RFC3339)

# Парсинг с несколькими возможными форматами
event.as_string("ECS.Timestamp").parse_time([time_layout.RFC3339, time_layout.DateTime])

# Округление до часа
now().truncate(duration("1h"))

IP-адреса и CIDR

ФункцияВозвратОписание
v.in_cidr(cidr)boolПроверить вхождение IP-адреса в подсеть CIDR

Функция работает с:

  • string — IP-адрес как строка ("192.168.1.1")
  • bytes — IP-адрес как байты
  • list — список IP-адресов (возвращает true, если хотя бы один входит в CIDR)

Параметр CIDR: "10.0.0.0/8" или просто IP "10.0.0.1" (подразумевается /32).

Примеры

# Проверка IP источника
event.FwdIP.in_cidr("192.168.0.0/16")

# Проверка списка IP
event.AssetIPs.in_cidr("10.0.0.0/8")

# Комбинация условий
event.FwdIP.in_cidr("172.16.0.0/12") || event.FwdIP.in_cidr("10.0.0.0/8")

MIME-преобразования

ФункцияВозвратОписание
b.mime(type)dynПреобразовать байты через зарегистрированный MIME-обработчик

Поддерживаемые MIME-типы

MIME-типОписаниеВозврат
"application/gzip"Декомпрессия gzipbytes
"text/csv; header=present"Парсинг CSV с заголовкомlist(map(string, string))
"text/csv; header=absent"Парсинг CSV без заголовкаlist(list(string))
"application/x-ndjson"Парсинг newline-delimited JSONlist(dyn)
"application/zip"Извлечение ZIP-архиваmap ("File", "Comment")

Примеры

# Декомпрессия gzip
bytes(event.Raw).mime("application/gzip")

# Парсинг CSV с заголовком
bytes(event.Raw).mime("text/csv; header=present")

Коллекции

Макрос as

МакросОписание
v.as(var, expr)Привязать значение к переменной и вычислить выражение. Эквивалент [v].map(var, expr)[0]

Работа с картами (map)

ФункцияВозвратОписание
m.keys() / keys(m)listОтсортированный список ключей
m.values() / values(m)listСписок значений (отсортирован по ключам)
m.with(other)mapСлияние карт (все поля из other добавляются/заменяются)
m.with_replace(other)mapСлияние: только замена существующих полей
m.with_update(other)mapСлияние: только добавление новых полей (без перезаписи)
m.collate(path)list(dyn)Обход по пути через точку, сбор значений
m.collate(paths)list(dyn)Обход по нескольким путям
m.drop(path)mapУдалить поле по пути через точку
m.drop(paths)mapУдалить поля по нескольким путям
m.drop_empty()mapРекурсивно удалить пустые списки и карты

Работа со списками (list)

ФункцияВозвратОписание
l.min() / min(l)dynМинимальное значение
l.max() / max(l)dynМаксимальное значение
l.sum() / sum(l)int/doubleСумма элементов
min(a, b)dynМинимум из двух значений
max(a, b)dynМаксимум из двух значений
front(l, n)listПервые n элементов
tail(l)listВсе элементы после первого
tail(l, n)listВсе элементы после индекса n
l.zip(other) / zip(l, other)mapОбъединить два равных списка в карту
l.collate(path)list(dyn)Обход элементов по пути
l.drop(path)listУдалить поле из каждого элемента
l.drop_empty()listРекурсивно удалить пустые элементы

Стандартные расширения (ext.Lists, ext.Sets)

ФункцияВозвратОписание
l.flatten()listПлоский список из вложенных списков
l.slice(start, end)listСрез списка
l.sort()listСортировка
l.distinct()listУникальные элементы
sets.contains(l, sub)boolСодержит ли список все элементы подсписка
sets.intersects(a, b)boolЕсть ли общие элементы
sets.equivalent(a, b)boolЭквивалентны ли множества
math.greatest(a, b)dynМаксимум (ext.Math)
math.least(a, b)dynМинимум (ext.Math)

Примеры

# Создание карты из двух списков
["key1", "key2"].zip(["val1", "val2"]) # {"key1": "val1", "key2": "val2"}

# Слияние карт
{"a": 1}.with({"b": 2}) # {"a": 1, "b": 2}

# Извлечение значений по пути
data.collate("users.name") # собрать все имена из вложенной структуры

# Привязка промежуточного значения
event.Raw.re_find_submatch('user (\\w+)').as(parts, size(parts) > 1 ? parts[1] : '')

Обработка ошибок

ФункцияВозвратОписание
try(expr)dynЕсли expr — ошибка, возвращает строку ошибки; иначе — значение
try(expr, key)dynЕсли expr — ошибка, возвращает {key: "сообщение ошибки"}
is_error(expr)booltrue, если выражение — ошибка

Функции try и is_error являются нестрогими — они принимают ошибки как аргументы вместо того, чтобы прерывать вычисление.

Примеры

# Безопасное вычисление
try(event.as_string("Raw").decode_json())

# Проверка на ошибку
is_error(event.as_string("data").decode_json()) ? "invalid" : "valid"

# Ошибка с именованным ключом
try(event.Raw.decode_json(), "parse_error")

Агрегация (fold)

МакросОписание
list.fold(var, acc, init, expr)Свёртка списка: итерация с привязкой элемента к var, аккумулятор acc с начальным значением init, выражение expr на каждом шаге

Примеры

# Сумма списка
[1, 2, 3, 4].fold(x, acc, 0, acc + x) # 10

# Конкатенация строк
["a", "b", "c"].fold(x, acc, "", acc + x) # "abc"

Привязка переменных (cel.bind)

МакросОписание
cel.bind(var, init, expr)Привязать значение init к переменной var и вычислить expr

Примеры

# Привязка промежуточного результата
cel.bind(parts, event.Raw.re_find_submatch('user (\\w+) from (\\S+)'),
size(parts) > 2 ? parts[1] + "@" + parts[2] : "unknown"
)

# Условное присваивание
cel.bind(x, event.vars('Normalizer.Parts')[?2].orValue(''),
x == 'logged in' ? 'success'
: (x == 'authentication failed' ? 'failure' : 'unknown')
)

Опциональные типы

Поддержка опциональных типов позволяет безопасно работать с отсутствующими значениями.

ВыражениеОписание
list[?i]Безопасный доступ к элементу списка (возвращает optional)
map[?key]Безопасный доступ к ключу карты (возвращает optional)
opt.orValue(default)Получить значение или default, если отсутствует
optional.of(value)Создать optional со значением
optional.none()Создать пустой optional

Примеры

# Безопасный доступ к элементу списка
event.vars('parts')[?1].orValue('')

# Безопасный доступ к полю карты
data[?"optional_field"].orValue("default_value")

EQL-функции

Функции, совместимые с Elastic Query Language (EQL):

ФункцияВозвратОписание
eql_substring(s, start)stringПодстрока от позиции до конца (отрицательный индекс — с конца)
eql_substring(s, start, end)stringПодстрока [start:end)
eql_indexOf(s, sub)intИндекс первого вхождения подстроки (-1 если нет)
eql_indexOf(s, sub, start)intИндекс вхождения после позиции start
eql_between(s, left, right)stringТекст между левым и правым разделителями
eql_between(s, left, right, greedy)stringС жадным поиском правого разделителя
eql_between(s, left, right, greedy, insensitive)stringС жадным поиском и без учёта регистра