Пайпы LogsQL

Справочник пайпов LogsQL для обработки, трансформации и агрегации лог-записей.

Пайпы

Помимо фильтров, запрос LogsQL может содержать произвольную комбинацию действий, разделяемых символом |, — так называемых пайпов (pipes). Например, следующий запрос использует пайпы stats, sort и limit для получения топ-10 потоков логов с наибольшим количеством записей за последние 5 минут:

_time:5m | stats by (_stream) count() per_stream_logs | sort by (per_stream_logs desc) | limit 10

LogsQL поддерживает следующие пайпы:

  • block_stats — возвращает статистику по блокам данных.
  • blocks_count — подсчитывает количество блоков с логами, обработанных запросом.
  • collapse_nums — заменяет все десятичные и шестнадцатеричные числа на <N> в указанном поле.
  • copy — копирует поля логов (алиас: cp).
  • decolorize — удаляет ANSI-коды цвета из указанного поля.
  • delete — удаляет поля логов (алиасы: del, drop, rm).
  • drop_empty_fields — удаляет поля с пустыми значениями.
  • extract — извлекает текст в указанные поля по паттерну.
  • extract_regexp — извлекает текст с помощью регулярных выражений RE2.
  • facets — возвращает наиболее часто встречающиеся поля логов.
  • field_names — возвращает все имена полей логов.
  • field_values — возвращает все значения для указанного поля.
  • fields — выбирает указанный набор полей (алиас: keep).
  • filter — применяет дополнительные фильтры к результатам (алиас: where).
  • first — возвращает первые N записей после сортировки по указанным полям.
  • format — форматирует выходное поле на основе входных полей.
  • generate_sequence — генерирует выходные записи с целочисленной последовательностью.
  • join — объединяет результаты запросов по указанным полям.
  • json_array_len — возвращает длину JSON-массива в указанном поле.
  • hash — возвращает хеш значения указанного поля.
  • last — возвращает последние N записей после сортировки по указанным полям.
  • len — возвращает длину значения поля в байтах.
  • limit — ограничивает количество выбранных записей (алиас: head).
  • math — выполняет математические вычисления над полями (алиас: eval).
  • offset — пропускает указанное количество записей (алиас: skip).
  • pack_json — упаковывает поля в JSON-объект.
  • pack_logfmt — упаковывает поля в сообщение logfmt.
  • query_stats — возвращает статистику выполнения запроса.
  • rename — переименовывает поля логов (алиас: mv).
  • replace — заменяет подстроки в указанных полях.
  • replace_regexp — заменяет подстроки по регулярному выражению.
  • running_stats — выполняет скользящие статистические вычисления.
  • sample — возвращает случайную выборку логов.
  • set_stream_fields — устанавливает указанные поля как поля потока _stream.
  • sort — сортирует логи по указанным полям (алиас: order).
  • split — разбивает значение поля по разделителю.
  • stats — вычисляет различные статистики по выбранным логам.
  • stream_context — позволяет выбирать окружающие записи до и после совпавших логов в потоке.
  • time_add — добавляет указанную длительность к полю времени.
  • top — возвращает топ N наборов полей с максимальным количеством совпадений.
  • total_stats — выполняет глобальные статистические вычисления.
  • union — возвращает результаты нескольких LogsQL-запросов.
  • uniq — возвращает уникальные записи.
  • unpack_json — распаковывает JSON-сообщения из полей.
  • unpack_logfmt — распаковывает сообщения logfmt из полей.
  • unpack_syslog — распаковывает syslog-сообщения из полей.
  • unpack_words — извлекает слова из указанного поля.
  • unroll — разворачивает JSON-массивы в отдельные строки.

block_stats pipe

<q> | block_stats — пайп, возвращающий следующую статистику для каждого поля в каждом блоке данных, обработанном запросом <q>:

  • field — имя поля
  • rows — количество строк в блоке данных
  • type — внутренний тип хранения для данного поля
  • dict_items — количество уникальных значений в словаре для данного поля
  • dict_bytes — размер словарных данных на диске для данного поля
  • values_bytes — размер данных на диске для данного поля
  • bloom_bytes — размер данных блум-фильтра на диске для данного поля
  • _stream — поток логов для данного поля
  • part_path — путь к части данных, где хранятся данные поля

Пайп block_stats полезен преимущественно для целей отладки, например, для определения того, какое поле занимает больше всего места на диске.

См. также:


blocks_count pipe

<q> | blocks_count — пайп, подсчитывающий количество блоков с логами, обработанных запросом <q>. Этот пайп полезен преимущественно для отладки.

См. также:


collapse_nums pipe

<q> | collapse_nums at <field> — пайп, заменяющий все десятичные и шестнадцатеричные числа в указанном поле на заполнитель <N>. Например, если поле _msg содержит 2024-10-20T12:34:56Z request duration 1.34s, то оно будет заменено на <N>-<N>-<N>T<N>:<N>:<N>Z request duration <N>.<N>s следующим запросом:

_time:5m | collapse_nums at _msg

Суффикс at ... можно опустить, если collapse_nums применяется к полю _msg. Следующий запрос эквивалентен предыдущему:

_time:5m | collapse_nums

Эта функциональность полезна для поиска наиболее часто встречающихся паттернов в сообщениях логов с различными числами, включая: метки времени, IPv4-адреса, длительности запросов, размеры ответов, UUID, идентификаторы трассировок, идентификаторы пользователей и т.д. После применения collapse_nums сообщения с такими сущностями становятся идентичными, и к ним можно применить top pipe для получения наиболее часто встречающихся паттернов. Например, следующий запрос возвращает топ-5 наиболее частых паттернов за последний час:

_time:1h | collapse_nums | top 5 by (_msg)

collapse_nums может распознавать определённые паттерны в свёрнутых числах и заменять их соответствующими заполнителями, если добавить суффикс prettify:

  • <N>-<N>-<N>-<N>-<N> заменяется на <UUID>.
  • <N>.<N>.<N>.<N> заменяется на <IP4>.
  • <N>:<N>:<N> заменяется на <TIME>. Необязательные дробные секунды после времени считаются частью <TIME>.
  • <N>-<N>-<N> и <N>/<N>/<N> заменяются на <DATE>.
  • <N>-<N>-<N>T<N>:<N>:<N> и <N>-<N>-<N> <N>:<N>:<N> заменяются на <DATETIME>. Необязательная временная зона после даты-времени считается частью <DATETIME>.

Например, сообщение 2edfed59-3e98-4073-bbb2-28d321ca71a7 - [2024/12/08 15:21:02] 10.71.20.32 GET /foo 200 заменяется на <UUID> - [<DATETIME>] <IP4> GET /foo <N> при выполнении запроса:

_time:1h | collapse_nums prettify

Паттерны, возвращаемые collapse_nums prettify, могут использоваться в фильтре сопоставления по паттерну.

Если collapse_nums пропускает некоторые числа или сворачивает неожиданные числа, можно использовать условный collapse_nums для пропуска таких значений и их предварительной обработки с помощью replace_regexp.

См. также:

Условный collapse_nums

Если пайп collapse_nums должен применяться только к некоторым записям, добавьте if (<filters>) после collapse_nums. <filters> может содержать произвольные фильтры. Например, следующий запрос сворачивает числа в поле foo только если поле user_type равно admin:

_time:5m | collapse_nums if (user_type:=admin) at foo

copy pipe

Для копирования полей логов используйте | copy src1 as dst1, ..., srcN as dstN. Например, следующий запрос копирует поле host в server для логов за последние 5 минут, так что вывод содержит оба поля — host и server:

_time:5m | copy host as server

Можно копировать несколько полей одним пайпом. Например, следующий запрос копирует поле _time в timestamp, а поле _msg — в message:

_time:5m | copy _time as timestamp, _msg as message

Ключевое слово as необязательно.

Вместо copy можно использовать cp. Например, _time:5m | cp foo bar эквивалентно _time:5m | copy foo as bar.

Можно копировать несколько полей с одинаковым префиксом в поля с другим префиксом. Например, следующий запрос копирует все поля с префиксом foo в поля с префиксом bar:

_time:5m | copy foo* as bar*

См. также:


decolorize pipe

<q> | decolorize <field> — пайп, удаляющий ANSI-коды цвета из указанного поля по всем логам, возвращённым запросом <q>.

Поле <field> можно опустить, если ANSI-коды нужно удалить из поля _msg. Например, следующий запрос удаляет ANSI-коды из всех полей _msg за последние 5 минут:

_time:5m | decolorize

Этот запрос эквивалентен:

_time:5m | decolorize _msg

Рекомендуется удалять ANSI-коды цвета на этапе приёма данных — это упрощает дальнейшую работу с логами без необходимости применять | decolorize.

См. также:


delete pipe

Для удаления полей логов используйте | delete field1, ..., fieldN. Например, следующий запрос удаляет поля host и app из логов за последние 5 минут:

_time:5m | delete host, app

Вместо delete можно использовать drop, del и rm. Например, _time:5m | drop host эквивалентно _time:5m | delete host.

Можно удалять поля с общим префиксом. Например, следующий запрос удаляет все поля с префиксом foo:

_time:5m | delete foo*

См. также:


drop_empty_fields pipe

<q> | drop_empty_fields — пайп, удаляющий поля с пустыми значениями из результатов запроса <q>. Также пропускаются записи, в которых нет ни одного непустого поля.

Например, следующий запрос удаляет возможное пустое поле email, генерируемое пайпом extract, если поле foo не содержит email:

_time:5m | extract 'email: <email>,' from foo | drop_empty_fields

См. также:


extract pipe

<q> | extract "pattern" from field_name — пайп, извлекающий текст в выходные поля согласно паттерну из указанного поля field_name, возвращённого запросом <q>. Существующие поля остаются без изменений после применения | extract ....

Пайп extract полезен для извлечения дополнительных полей, необходимых для дальнейшей обработки другими пайпами, такими как stats или sort.

Например, следующий запрос выбирает логи со словом error за последний день, извлекает IP-адрес из поля _msg в поле ip, а затем вычисляет топ-10 IP-адресов с наибольшим количеством записей с помощью top pipe:

_time:1d error | extract "ip=<ip> " from _msg | top 10 (ip)

Ожидается, что поле _msg содержит подстроку ip=..., оканчивающуюся пробелом. Например, error ip=1.2.3.4 from user_id=42. Если такой подстроки нет, выходное поле ip будет пустым.

Если пайп extract применяется к полю _msg, то часть from _msg можно опустить. Следующий запрос эквивалентен предыдущему:

_time:1d error | extract "ip=<ip> " | top 10 (ip)

Если паттерн содержит двойные кавычки, поставьте \ перед ними или заключите паттерн в одинарные кавычки. Например, следующий запрос извлекает ip из соответствующего JSON-поля:

_time:5m | extract '"ip":"<ip>"'

Добавьте keep_original_fields в конец extract ..., чтобы сохранить оригинальные непустые значения полей, упомянутых в паттерне, вместо их перезаписи извлечёнными значениями:

_time:5m | extract 'ip=<ip> ' keep_original_fields

По умолчанию extract записывает пустые совпавшие поля в вывод, что может перезаписать существующие значения. Добавьте skip_empty_results в конец extract ..., чтобы предотвратить перезапись:

_time:5m | extract 'ip=<ip> ' from foo skip_empty_results

Совет по производительности: рекомендуется использовать более специфичные фильтры логов для уменьшения количества записей, передаваемых в extract.

См. также:

Формат паттерна для extract pipe

Часть pattern в пайпе extract имеет следующий формат:

text1<field1>text2<field2>...textN<fieldN>textN+1

Где text1, …, textN+1 — произвольный текст, который сопоставляется с входным текстом как есть. Текст-разделитель между заполнителями (text2, …, textN) должен быть непустым, тогда как text1 и textN+1 могут быть пустыми.

field1, …, fieldN — заполнители, которые сопоставляются с подстрокой любой длины (включая нулевую) во входном тексте до следующего textX. Заполнители могут быть анонимными и именованными. Анонимные записываются как <>, <_> или <*>. Они используются, когда часть входного текста нужно пропустить. Именованные записываются как <some_name>, где some_name — имя поля для сохранения найденной подстроки.

Сопоставление начинается с первого вхождения text1 во входном тексте. Если паттерн начинается с <field1> и не содержит text1, сопоставление начинается с начала входного текста. Если какой-либо textX не найден в оставшемся тексте, оставшиеся именованные заполнители получают пустые строки.

Например, если поле _msg содержит:

1.2.3.4 GET /foo/bar?baz 404 "Mozilla  foo bar baz" some tail here

То следующий паттерн извлечёт поля ip, path и user_agent:

<ip> <_> <path> <_> "<user_agent>"

Платформа автоматически обнаруживает строки в кавычках и корректно разбирает их, если первый совпадающий символ заполнителя — одинарная кавычка, двойная кавычка или обратная кавычка. Поэтому лучше использовать следующий паттерн для правильного сопоставления user_agent в кавычках:

<ip> <_> <path> <_> <user_agent>

Это полезно для извлечения JSON-строк. Например, следующий паттерн корректно извлекает JSON-строку message в поле msg:

"message":<msg>

Автоматическое снятие кавычек можно отключить, добавив префикс plain: перед именем поля:

some json string array: [<plain:json_array>]

Если в паттерне нужно сопоставить специальные символы, такие как <, их можно экранировать с помощью HTML-сущностей. Например, паттерн для сопоставления текста a < b:

<left> &lt; <right>

Условный extract

Если пайп extract должен применяться только к некоторым записям, добавьте if (<filters>) после слова extract. <filters> может содержать произвольные фильтры. Например, следующий запрос извлекает поле ip из _msg только если поле ip отсутствует или пусто:

_time:5m | extract if (ip:"") "ip=<ip> "

Альтернативный подход — добавить keep_original_fields в конец extract, чтобы сохранить оригинальные непустые значения:

_time:5m | extract "ip=<ip> " keep_original_fields

extract_regexp pipe

<q> | extract_regexp "pattern" from field_name — пайп, извлекающий подстроки из поля field_name по регулярному выражению RE2 и сохраняющий их в именованные поля. Паттерн должен содержать именованные группы захвата вида (?P<capture_field_name>...).

Например, следующий запрос извлекает подстроки, похожие на IPv4-адреса, из поля _msg в поле ip для логов за последние 5 минут:

_time:5m | extract_regexp "(?P<ip>([0-9]+[.]){3}[0-9]+)" from _msg

Часть from _msg можно опустить, если извлечение выполняется из поля _msg:

_time:5m | extract_regexp "(?P<ip>([0-9]+[.]){3}[0-9]+)"

Добавьте keep_original_fields для сохранения оригинальных непустых значений:

_time:5m | extract_regexp 'ip=(?P<ip>([0-9]+[.]){3}[0-9]+)' keep_original_fields

Добавьте skip_empty_results для предотвращения перезаписи существующих значений пустыми:

_time:5m | extract_regexp 'ip=(?P<ip>([0-9]+[.]){3}[0-9]+)' from foo skip_empty_results

Совет по производительности: рекомендуется использовать пайп extract вместо extract_regexp для достижения более высокой производительности запросов.

См. также:

Условный extract_regexp

Если пайп extract_regexp должен применяться только к некоторым записям, добавьте if (<filters>) после слова extract_regexp. Например, следующий запрос извлекает ip из поля _msg только если поле ip отсутствует или пусто:

_time:5m | extract_regexp if (ip:"") "ip=(?P<ip>([0-9]+[.]){3}[0-9]+)"

Альтернативный подход — добавить keep_original_fields:

_time:5m | extract_regexp "ip=(?P<ip>([0-9]+[.]){3}[0-9]+)" keep_original_fields

facets pipe

<q> | facets — пайп, возвращающий наиболее часто встречающиеся непустые значения для каждого поля, обнаруженного в результатах запроса <q>. Также возвращается приблизительное количество совпадений для каждой пары поле=значение.

Например, следующий запрос возвращает наиболее частые значения для каждого поля среди логов со словом error за последний час:

_time:1h error | facets

Можно указать количество возвращаемых значений для каждого поля с помощью синтаксиса facets N:

_time:1h error | facets 3

По умолчанию facets не возвращает поля со слишком большим количеством уникальных значений. Лимит можно изменить через суффикс max_values_per_field M:

_time:1h error | facets 15 max_values_per_field 100000

По умолчанию facets не возвращает поля со слишком длинными значениями. Лимит можно изменить через суффикс max_value_len K:

_time:1h error | facets max_value_len 100

По умолчанию facets не возвращает поля, содержащие единственное константное значение, так как такие фасеты обычно неинтересны. Добавьте суффикс keep_const_fields для включения таких полей:

_time:1h error | facets keep_const_fields

См. также:


field_names pipe

<q> | field_names — пайп, возвращающий все имена полей логов с приблизительным количеством записей для каждого имени из результатов запроса <q>.

Например, следующий запрос возвращает все имена полей с количеством совпавших записей за последние 5 минут:

_time:5m | field_names

Имена полей возвращаются в произвольном порядке. Используйте пайп sort для сортировки при необходимости.

См. также:


field_values pipe

<q> | field_values field_name — пайп, возвращающий все значения для указанного поля field_name с количеством записей для каждого значения.

Например, следующий запрос возвращает все значения поля level с количеством совпадений за последние 5 минут:

_time:5m | field_values level

Можно ограничить количество возвращаемых значений, добавив limit N:

_time:5m | field_values user_id limit 10

Если лимит достигнут, возвращается произвольный набор значений, а количество совпадений устанавливается в 0, так как оно может быть некорректным.

См. также:


fields pipe

По умолчанию все поля логов возвращаются в ответе. Можно выбрать определённый набор полей с помощью | fields field1, ..., fieldN.

Например, следующий запрос выбирает только поля host и _msg из логов за последние 5 минут:

_time:5m | fields host, _msg

Вместо fields можно использовать keep:

_time:5m | keep host, _msg

Можно использовать подстановочные префиксы. Например, следующий запрос сохраняет все поля с именами, начинающимися на foo:

_time:5m | fields foo*

См. также:


filter pipe

<q> | filter ... — пайп, фильтрующий логи, возвращённые запросом <q>, с помощью дополнительного фильтра.

Например, следующий запрос возвращает значения поля host, если количество сообщений со словом error за последний час превышает 1000:

_time:1h error | stats by (host) count() logs_count | filter logs_count:> 1_000

Вместо filter можно использовать where:

_time:1h error | stats by (host) count() logs_count | where logs_count:> 1_000

Префикс filter можно опустить, если используемые фильтры не конфликтуют с именами пайпов:

_time:1h error | stats by (host) count() logs_count | logs_count:> 1_000

См. также:


first pipe

<q> | first N by (fields) — пайп, возвращающий первые N записей из результатов запроса <q> после сортировки по указанным полям.

Пайп first N является сокращением для сортировки и взятия верхних N строк за один шаг (эквивалент sort ... | limit N).

  • Если first используется с by (...), возвращаются топ N строк по указанным ключам сортировки.
  • Если first используется без ключей сортировки, возвращаются топ N строк после сортировки по всем полям.

Например, следующий запрос возвращает первые 10 записей с наименьшим значением request_duration за последние 5 минут:

_time:5m | first 10 by (request_duration)

Можно возвращать до N записей индивидуально для каждой группы с одинаковым набором полей через partition by (...):

_time:1h | first 3 by (request_duration) partition by (host)

См. также:


format pipe

<q> | format "pattern" as result_field — пайп, комбинирующий поля логов из результатов запроса <q> согласно паттерну и сохраняющий результат в result_field.

Например, следующий запрос сохраняет текст request from <ip>:<port> в поле _msg, подставляя значения полей <ip> и <port>:

_time:5m | format "request from <ip>:<port>" as _msg

Если результат сохраняется в поле _msg, часть as _msg можно опустить:

_time:5m | format "request from <ip>:<port>"

Строковые поля поддерживают дополнительные правила форматирования:

  • Количество секунд из значения длительности — добавьте duration_seconds: перед именем поля.

  • JSON-совместимая строка в кавычках — добавьте q: перед именем поля:

    _time:5m | format '{"_msg":<q:_msg>,"stacktrace":<q:stacktrace>}' as my_json
    
  • Преобразование в верхний и нижний регистр — добавьте uc: или lc: перед именем поля:

    _time:5m | format 'uppercase foo: <uc:foo>, lowercase bar: <lc:bar>' as result
    
  • URL-кодирование и декодирование — добавьте urlencode: или urldecode: перед именем поля:

    _time:5m | format 'url: http://foo.com/?user=<urlencode:user>'
    
  • Hex-кодирование и декодирование — добавьте hexencode: или hexdecode: перед именем поля:

    _time:5m | format 'hex-encoded password: <hexencode:password>'
    
  • Base64-кодирование и декодирование — добавьте base64encode: или base64decode: перед именем поля:

    _time:5m | format 'base64-encoded password: <base64encode:password>'
    
  • Преобразование шестнадцатеричного числа в десятичное — добавьте hexnumdecode: перед именем поля. Например, format "num=<hexnumdecode:some_hex_field>".

Числовые поля могут быть преобразованы в следующие строковые представления:

  • Время RFC3339 — добавьте time: перед именем поля, содержащего Unix-метку времени. Числовая метка может быть в секундах, миллисекундах, микросекундах или наносекундах — точность определяется автоматически. Например, format "time=<time:timestamp>".
  • Читаемая длительность — добавьте duration: перед числовым полем, содержащим длительность в наносекундах. Например, format "duration=<duration:duration_nsecs>".
  • IPv4 — добавьте ipv4: перед полем, содержащим uint32-представление IPv4-адреса. Например, format "ip=<ipv4:ip_num>".
  • Шестнадцатеричное 64-битное число с дополнением нулями — добавьте hexnumencode: перед именем поля. Например, format "hex_num=<hexnumencode:some_field>".

Добавьте keep_original_fields, чтобы сохранить оригинальное непустое значение result_field:

_time:5m | format 'some_text' as foo keep_original_fields

Добавьте skip_empty_results, чтобы пустые результаты не записывались в вывод:

_time:5m | format "<field1><field2>" as foo skip_empty_results

Совет по производительности: рекомендуется использовать более специфичные фильтры для уменьшения количества записей, передаваемых в format.

См. также:

Условный format

Если пайп format должен применяться только к некоторым записям, добавьте if (<filters>) сразу после слова format. Например, следующий запрос сохраняет отформатированный результат в поле message только если поля ip и host непусты:

_time:5m | format if (ip:* and host:*) "request from <ip>:<host>" as message

generate_sequence pipe

<q> | generate_sequence <N> — пайп, который пропускает все результаты <q> и генерирует <N> выходных записей с полем _msg, содержащим целочисленную последовательность от 0 до N-1.

Этот пайп полезен для тестирования и отладки. Например, следующий запрос генерирует 1000 случайных целых чисел в диапазоне [0..9] и собирает статистику по количеству совпадений для каждого случайного числа:

* | generate_sequence 1000
    | math round(rand()*10) as rand_num
    | stats by (rand_num) count() hits
    | sort by (rand_num)

См. также:


join pipe

<q1> | join by (<fields>) (<q2>) — пайп, объединяющий результаты запроса <q1> с результатами <q2> по указанному набору полей. Работает следующим образом:

  1. Выполняет запрос <q2> и запоминает его результаты.
  2. Для каждой входной строки из <q1> ищет совпадающие строки в результатах <q2> по указанным полям.
  3. Если совпадающих строк нет, входная строка передаётся в вывод как есть.
  4. Если совпадающие строки найдены, входная строка расширяется новыми полями из каждой совпадающей строки.

Логика аналогична LEFT JOIN в SQL. Например, следующий запрос возвращает количество логов по пользователям для двух приложений — app1 и app2:

_time:1d {app="app1"} | stats by (user) count() app1_hits
  | join by (user) (
    _time:1d {app="app2"} | stats by (user) count() app2_hits
  )

Для результатов, аналогичных INNER JOIN, добавьте суффикс inner:

_time:1d {app="app1"} | stats by (user) count() app1_hits
  | join by (user) (
    _time:1d {app="app2"} | stats by (user) count() app2_hits
  ) inner

Можно добавить префикс ко всем полям, возвращаемым подзапросом, указав его после подзапроса:

_time:1d {app="app1"} | stats by (user) count() app1_hits
  | join by (user) (
    _time:1d {app="app2"} | stats by (user) count() app2_hits
  ) prefix "app2."

Советы по производительности:

  • Убедитесь, что подзапрос в join возвращает относительно небольшое количество результатов, так как они хранятся в оперативной памяти.
  • Условный stats обычно выполняется быстрее и требует меньше памяти, чем аналогичный join.

См. также:


json_array_len pipe

<q> | json_array_len(field) as result_field — вычисляет длину JSON-массива в указанном поле и сохраняет результат в result_field.

Например, следующий запрос возвращает топ-5 записей с наибольшим количеством слов в сообщениях за последние 5 минут:

_time:5m | unpack_words _msg as words | json_array_len (words) as words_count | first 5 (words_count desc)

См. также:


hash pipe

<q> | hash(field) as result_field — вычисляет целочисленный хеш значения указанного поля и сохраняет его в result_field.

Например, следующий запрос вычисляет хеш поля user_id и сохраняет результат в поле user_id_hash для логов за последние 5 минут:

_time:5m | hash(user_id) as user_id_hash

См. также:


last pipe

<q> | last N by (fields) — пайп, возвращающий последние N записей из результатов запроса <q> после сортировки по указанным полям.

Например, следующий запрос возвращает последние 10 записей с наибольшим значением request_duration за последние 5 минут:

_time:5m | last 10 by (request_duration)

Можно возвращать до N записей для каждой группы через partition by (...):

_time:1h | last 3 by (request_duration) partition by (host)

См. также:


len pipe

<q> | len(field) as result — пайп, сохраняющий длину значения поля field в байтах в поле result.

Например, следующий запрос показывает топ-5 записей с наибольшей длиной поля _msg за последние 5 минут:

_time:5m | len(_msg) as msg_len | sort by (msg_len desc) | limit 5

См. также:


limit pipe

Если нужно обработать только подмножество выбранных записей, используйте | limit N. Например, следующий запрос возвращает до 100 записей за последние 5 минут:

_time:5m | limit 100

Вместо limit можно использовать head. Например, _time:5m | head 100 эквивалентно _time:5m | limit 100.

Значение N в limit N / head N можно опустить — в этом случае возвращается до 10 записей:

error | head

По умолчанию строки выбираются в произвольном порядке для повышения производительности. Используйте пайп sort для обеспечения определённого порядка перед применением limit.

См. также:


math pipe

<q> | math ... — пайп для выполнения математических вычислений над числовыми значениями полей логов. Формат:

| math
  expr1 as resultName1,
  ...
  exprN as resultNameN

Где exprX — поддерживаемое математическое выражение, а resultNameX — имя поля для сохранения результата. Ключевое слово as необязательно.

exprX может ссылаться на resultNameY, вычисленный ранее.

Например, следующий запрос делит значение duration_msecs на 1000, округляет до целого и сохраняет в duration_secs:

_time:5m | math round(duration_msecs / 1000) as duration_secs

Поддерживаемые математические операции:

  • arg1 + arg2 — сумма
  • arg1 - arg2 — разность
  • arg1 * arg2 — произведение
  • arg1 / arg2 — деление
  • arg1 % arg2 — остаток от деления
  • arg1 ^ arg2 — возведение в степень
  • arg1 & arg2 — побитовое И (аргументы в диапазоне [0 .. 2^53-1])
  • arg1 or arg2 — побитовое ИЛИ (аргументы в диапазоне [0 .. 2^53-1])
  • arg1 xor arg2 — побитовое исключающее ИЛИ (аргументы в диапазоне [0 .. 2^53-1])
  • arg1 default arg2 — возвращает arg2, если arg1 не является числовым или равен NaN
  • abs(arg) — абсолютное значение
  • ceil(arg) — наименьшее целое, большее или равное arg
  • exp(arg) — возведение числа e в степень arg
  • floor(arg) — наибольшее целое, меньшее или равное arg
  • ln(arg) — натуральный логарифм
  • max(arg1, ..., argN) — максимальное значение
  • min(arg1, ..., argN) — минимальное значение
  • now() — текущая Unix-метка времени в наносекундах
  • rand() — псевдослучайное число в диапазоне [0...1)
  • round(arg) — округление до целого. Принимает необязательный аргумент nearest для округления до ближайшего кратного. Например, round(temperature, 0.1) округляет до одного знака после запятой.

Каждый аргумент argX может содержать:

  • Имя поля лога. Например, errors_total / requests_total. Поле парсится как числовое значение, как Unix-метка времени в наносекундах (если содержит RFC3339 время), или как uint32 (если содержит IPv4-адрес). В остальных случаях парсится как NaN.
  • Любое числовое значение, RFC3339 время или IPv4-адрес. Например, 1MiB, "2024-05-15T10:20:30.934324Z" или "12.34.56.78".
  • Другое математическое выражение в скобках. Например, (a + b) * c.

Время, длительность и IPv4-адрес можно преобразовать обратно в строку с помощью пайпа format:

_time:5m | math round(request_duration, 1e9) as request_duration_nsecs | format '<duration:request_duration_nsecs>' as request_duration

Вместо math можно использовать eval:

_time:5m | eval (duration_secs * 1000) as duration_msecs

См. также:


offset pipe

Если некоторые записи нужно пропустить после sort, используйте | offset N. Например, следующий запрос пропускает первые 100 записей за последние 5 минут после сортировки по _time:

_time:5m | sort by (_time) | offset 100

Вместо offset можно использовать skip. Например, _time:5m | skip 10 эквивалентно _time:5m | offset 10.

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

См. также:


pack_json pipe

<q> | pack_json as field_name — пайп, упаковывающий все поля каждой записи в JSON-объект и сохраняющий его как строку в field_name.

Например, следующий запрос упаковывает все поля в JSON и сохраняет в поле _msg для логов за последние 5 минут:

_time:5m | pack_json as _msg

Часть as _msg можно опустить, если JSON сохраняется в поле _msg:

_time:5m | pack_json

Если нужно упаковать только часть полей, перечислите их в fields (...):

_time:5m | pack_json fields (foo, bar) as baz

Можно указать префиксы полей:

_time:5m | pack_json fields (foo.*, bar.*) as baz

Пайп pack_json не модифицирует и не удаляет другие поля. Чтобы оставить только упакованное поле, добавьте | fields ...:

_time:5m | pack_json as foo | fields foo

См. также:


pack_logfmt pipe

<q> | pack_logfmt as field_name — пайп, упаковывающий все поля каждой записи в сообщение формата logfmt и сохраняющий его как строку в field_name.

Например, следующий запрос упаковывает все поля в logfmt и сохраняет в поле _msg:

_time:5m | pack_logfmt as _msg

Часть as _msg можно опустить:

_time:5m | pack_logfmt

Если нужно упаковать только часть полей, перечислите их в fields (...):

_time:5m | pack_logfmt fields (foo, bar) as baz

Можно указать префиксы полей:

_time:5m | pack_logfmt fields (foo.*, bar.*) as baz

Пайп pack_logfmt не модифицирует и не удаляет другие поля. Чтобы оставить только упакованное поле:

_time:5m | pack_logfmt as foo | fields foo

См. также:


query_stats pipe

<q> | query_stats — пайп, возвращающий следующую статистику выполнения запроса <q>:

  • BytesReadColumnsHeaders — количество байт, прочитанных с диска для заголовков столбцов. Используйте пайп fields для уменьшения этого значения.
  • BytesReadColumnsHeaderIndexes — количество байт для индексов заголовков столбцов.
  • BytesReadBloomFilters — количество байт для блум-фильтров.
  • BytesReadValues — количество байт для значений полей. Используйте пайп fields для уменьшения.
  • BytesReadTimestamps — количество байт для поля _time.
  • BytesReadBlockHeaders — количество байт для заголовков блоков.
  • BytesReadTotal — общее количество байт, прочитанных с диска.
  • BlocksProcessed — количество обработанных блоков данных. Используйте более узкий фильтр времени и фильтр потоков для уменьшения.
  • RowsProcessed — количество обработанных записей.
  • RowsFound — количество найденных записей.
  • ValuesRead — количество прочитанных значений полей.
  • TimestampsRead — количество прочитанных полей _time.
  • BytesProcessedUncompressedValues — количество несжатых байт значений полей, обработанных при выполнении запроса.
  • QueryDurationNsecs — длительность запроса в наносекундах. Может использоваться для вычисления скоростей обработки с помощью пайпа math.

Этот пайп полезен для исследования и оптимизации медленных запросов.

См. также:


rename pipe

Для переименования полей логов используйте | rename src1 as dst1, ..., srcN as dstN. Например, следующий запрос переименовывает поле host в server:

_time:5m | rename host as server

Можно переименовывать несколько полей одним пайпом:

_time:5m | rename host as instance, app as job

Ключевое слово as необязательно.

Вместо rename можно использовать mv. Например, _time:5m | mv foo bar эквивалентно _time:5m | rename foo as bar.

Можно переименовать несколько полей с общим префиксом:

_time:5m | rename foo* as bar*

Можно удалить общий префикс:

_time:5m | rename foo* as *

Можно добавить общий префикс ко всем полям:

_time:5m | rename * as foo*

См. также:


replace pipe

<q> | replace ("old", "new") at field — пайп, заменяющий все вхождения подстроки old на new в указанном поле.

Например, следующий запрос заменяет все secret-password на *** в поле _msg за последние 5 минут:

_time:5m | replace ("secret-password", "***") at _msg

Часть at _msg можно опустить, если замена производится в поле _msg:

_time:5m | replace ("secret-password", "***")

Количество замен можно ограничить с помощью limit N. Например, следующий запрос заменяет только первое вхождение foo на bar в поле baz:

_time:5m | replace ('foo', 'bar') at baz limit 1

Совет по производительности: рекомендуется использовать более специфичные фильтры для уменьшения количества записей, передаваемых в replace.

См. также:

Условный replace

Если пайп replace должен применяться только к некоторым записям, добавьте if (<filters>) после replace. Например, следующий запрос заменяет secret на *** в поле password только если user_type равно admin:

_time:5m | replace if (user_type:=admin) ("secret", "***") at password

replace_regexp pipe

<q> | replace_regexp ("regexp", "replacement") at field — пайп, заменяющий все подстроки, совпадающие с regexp, на replacement в указанном поле.

regexp должен содержать регулярное выражение в синтаксисе RE2. replacement может содержать заполнители $N или ${N}, которые подставляются из N-й группы захвата.

Например, следующий запрос заменяет все подстроки, начинающиеся с host- и заканчивающиеся на -foo, содержимым между ними в поле _msg:

_time:5m | replace_regexp ("host-(.+?)-foo", "$1") at _msg

Часть at _msg можно опустить:

_time:5m | replace_regexp ("host-(.+?)-foo", "$1")

Количество замен можно ограничить с помощью limit N:

_time:5m | replace_regexp ('password: [^ ]+', '') at baz limit 1

Советы по производительности:

  • Рекомендуется использовать пайп replace вместо replace_regexp, если это возможно, так как он работает быстрее.
  • Рекомендуется использовать более специфичные фильтры для уменьшения количества записей, передаваемых в replace_regexp.

См. также:

Условный replace_regexp

Если пайп replace_regexp должен применяться только к некоторым записям, добавьте if (<filters>) после replace_regexp. Например, следующий запрос заменяет подстроки password: ..., оканчивающиеся пробелом, на *** в поле foo только если user_type равно admin:

_time:5m | replace_regexp if (user_type:=admin) ("password: [^ ]+", "***") at foo

running_stats pipe

<q> | running_stats ... — пайп, вычисляющий скользящую статистику (скользящий счётчик, скользящую сумму и т.д.) по указанным полям логов и сохраняющий результат в указанных полях для каждой входной записи.

Скользящая статистика вычисляется по логам, отсортированным по времени, поэтому <q> должен возвращать поле _time.

Пайп running_stats сохраняет все логи в памяти, поэтому убедитесь, что <q> возвращает ограниченное количество записей.

Например, следующий запрос вычисляет скользящую сумму поля hits за последние 5 минут:

_time:5m | running_stats sum(hits) as running_hits

Базовый формат:

... | running_stats
  stats_func1(...) as result_name1,
  ...
  stats_funcN(...) as result_nameN

Например, следующий запрос вычисляет скользящий счётчик и скользящую сумму hits:

_time:5m
    | running_stats
        count() as running_logs,
        sum(hits) as running_hits

Имя результата можно опустить:

_time:5m | running_stats count(), sum(hits)

Полезно комбинировать running_stats со статистикой по временным интервалам. Например, следующий запрос возвращает почасовое количество логов за последний день плюс скользящее суммарное количество:

_time:1d
    | stats by (_time:hour) count() as hits
    | running_stats sum(hits) as running_hits

Поддерживаемые функции running_stats:

  • count() — скользящее количество записей. Можно указать поле: count(fieldName) — считает записи с непустым значением поля. Можно указать несколько полей или префикс: count(foo*).
  • max(field1, ..., fieldN) — скользящий максимум. Поддерживает max(prefix*).
  • min(field1, ..., fieldN) — скользящий минимум. Отсутствующие поля считаются пустыми строками. Поддерживает min(prefix*).
  • sum(field1, ..., fieldN) — скользящая сумма числовых значений. Нечисловые значения пропускаются. Если числовых значений нет, возвращается NaN. Поддерживает sum(prefix*).

См. также:

running_stats по полям

Для вычисления независимой скользящей статистики для каждой группы полей используйте:

<q> | running_stats by (field1, ..., fieldM)
  stats_func1(...) as result_name1,
  ...
  stats_funcN(...) as result_nameN

Например, следующий запрос вычисляет скользящий счётчик и скользящую сумму hits, сгруппированные по полям (host, path):

_time:5m
    | running_stats by (host, path)
        count() running_logs,
        sum(hits) running_hits

Ключевое слово by можно опустить:

_time:5m | running_stats (host, path) count() running_logs, sum(hits) running_hits

См. также:


sample pipe

<q> | sample N — пайп, возвращающий случайную выборку 1/N от всех записей запроса <q>.

Например, следующий запрос возвращает примерно 1% (1/100) логов со словом error за последний час:

_time:1h error | sample 100

См. также:


set_stream_fields pipe

| set_stream_fields field1, ..., fieldN — пайп, устанавливающий указанные поля как поля потока _stream.

Например, если логи имеют host="foo" и path="/bar", следующий запрос устанавливает _stream в {host="foo", path="/bar"}:

_time:5m | set_stream_fields host, path

См. также:

Условный set_stream_fields

Пайп set_stream_fields может применяться к подмножеству записей через if (...). Например, следующий запрос обновляет _stream только для записей с host="foobar":

_time:5m | set_stream_fields if (host:="foobar") host, app

sort pipe

По умолчанию логи выбираются в произвольном порядке для повышения производительности. Для сортировки используйте <q> | sort by (field1, ..., fieldN) с естественной сортировкой.

Например, следующий запрос сортирует логи за последние 5 минут по _stream и затем по _time:

_time:5m | sort by (_stream, _time)

Добавьте desc после поля для сортировки в обратном порядке:

_time:5m | sort by (request_duration_seconds desc)

Обратный порядок можно применить глобально:

_time:5m | sort by (foo, bar) desc

Ключевое слово by можно опустить:

_time:5m | sort (foo, bar) desc

Вместо sort можно использовать order:

_time:5m | order by (foo, bar) desc

Для ограничения количества результатов добавьте limit N — это уменьшает потребление памяти:

_time:1h | sort by (request_duration desc) limit 10

Этот запрос эквивалентен:

_time:1h | last 10 by (request_duration)

Для пропуска первых N результатов добавьте offset N:

_time:1h | sort by (request_duration desc) offset 10 limit 20

Можно применять сортировку и limit индивидуально для каждой группы через partition by (...):

_time:1h | sort by (request_duration desc) partition by (host) limit 3

Для добавления ранга (номера позиции) используйте rank as <fieldName>:

_time:5m | sort by (_time) rank as position

Сортировка большого количества записей может быть медленной и потреблять много памяти. Рекомендуется:

  • Добавлять limit N в конец sort.
  • Сужать временной диапазон.
  • Использовать более специфичные фильтры.
  • Ограничивать количество полей через fields.

См. также:


split pipe

<q> | split <separator> from <src_field> as <dst_field> — пайп, разбивающий значение поля <src_field> по разделителю <separator> и сохраняющий результат как JSON-массив в <dst_field>.

Например, следующий запрос разбивает сообщения логов по запятой и сохраняет результат в поле items:

_time:5m | split "," from _msg as items

Часть as <dst_field> необязательна — если опущена, результат сохраняется в исходном поле:

_time:5m | split "," from _msg

Часть from <src_field> необязательна — если опущена, используется поле _msg:

_time:5m | split ","

Удобно использовать unroll для развёртывания JSON-массива. Например, топ-5 наиболее частых элементов, разделённых запятыми:

_time:5m | split "," as items | unroll items | top 5 (items)

См. также:


stats pipe

<q> | stats ... — пайп для вычисления различных статистик по логам, возвращённым запросом <q>.

Например, следующий запрос подсчитывает количество логов за последние 5 минут с помощью функции count:

_time:5m | stats count() as logs_total

Базовый формат:

... | stats
  stats_func1(...) as result_name1,
  ...
  stats_funcN(...) as result_nameN

Где stats_func* — любая из поддерживаемых функций статистики, а result_name* — имя поля для сохранения результата. Ключевое слово as необязательно.

Например, следующий запрос вычисляет количество логов и уникальных потоков за последние 5 минут:

_time:5m | stats count() logs_total, count_uniq(_stream) streams_total

Префикс stats можно опустить:

_time:5m | count() logs_total, count_uniq(_stream) streams_total

Имя результата можно опустить — в этом случае используется строковое представление функции:

_time:5m | count(), count_uniq(_stream)

См. также:

Статистика по полям

Для вычисления независимых статистик для каждой группы полей используйте:

<q> | stats by (field1, ..., fieldM)
  stats_func1(...) as result_name1,
  ...
  stats_funcN(...) as result_nameN

Например, количество логов и уникальных IP за последние 5 минут, сгруппированных по (host, path):

_time:5m | stats by (host, path) count() logs_total, count_uniq(ip) ips_total

Ключевое слово by можно опустить:

_time:5m | stats (host, path) count() logs_total, count_uniq(ip) ips_total

См. также:

Статистика по временным интервалам

Для вычисления статистик, сгруппированных по временным интервалам:

<q> | stats by (_time:step)
  stats_func1(...) as result_name1,
  ...
  stats_funcN(...) as result_nameN

Где step может иметь любое значение длительности. Например, поминутная статистика за последние 5 минут:

_time:5m | stats by (_time:1m) count() logs_total, count_uniq(ip) ips_total

Полезно комбинировать со скользящей статистикой через running_stats:

_time:5m
    | stats by (_time:1m) count() as hits
    | running_stats sum(hits) as running_hits

Полезно комбинировать с глобальной статистикой через total_stats для вычисления процентов:

_time:5m
    | stats by (_time:1m) count() as hits
    | total_stats sum(hits) as total_hits
    | math round((hits / total_hits)*100) as hits_percent

Поддерживаемые значения step:

  • nanosecond — эквивалент 1ns
  • microsecond — эквивалент 1us
  • millisecond — эквивалент 1ms
  • second — эквивалент 1s
  • minute — эквивалент 1m
  • hour — эквивалент 1h
  • day — эквивалент 1d
  • week — эквивалент 1w
  • month — один месяц (с учётом количества дней)
  • year — один год (с учётом количества дней)

См. также:

Статистика по временным интервалам со смещением часового пояса

Хранилище логов хранит значения _time как Unix-время в наносекундах (UTC). Иногда требуется группировка по дням или неделям в другом часовом поясе:

<q> | stats by (_time:step offset timezone_offset) ...

Например, подневная статистика за последнюю неделю в часовом поясе UTC+02:00:

_time:1w | stats by (_time:1d offset 2h) count() logs_total

См. также:

Статистика по интервалам полей

Каждое поле внутри <q> | stats by (...) может быть разделено на интервалы аналогично полю _time. Любое числовое значение может использоваться как step.

Например, количество запросов за последний час по интервалам в 10КБ поля request_size_bytes:

_time:1h | stats by (request_size_bytes:10KB) count() requests

См. также:

Статистика по IPv4-интервалам

Статистику можно группировать по полю с IPv4-адресами через синтаксис ip_field_name:/network_mask.

Например, количество записей по подсетям /24 из поля ip за последние 5 минут:

_time:5m | stats by (ip:/24) count() requests_per_subnet

См. также:

Статистика с дополнительными фильтрами

Иногда нужно вычислить статистику по разным подмножествам записей. Это делается вставкой условия if (<any_filters>) между функцией статистики и именем результата.

Например, подсчёт сообщений с GET, POST и PUT плюс общее количество за последние 5 минут:

_time:5m | stats
  count() if (GET) gets,
  count() if (POST) posts,
  count() if (PUT) puts,
  count() total

Если ни одна входная строка не соответствует фильтру if (...), функция вычисляется для пустого набора. Например, count(*) возвращает 0, а sum(...) и avg(...) возвращают NaN.

См. также:


stream_context pipe

<q> | stream_context ... — пайп, позволяющий выбирать окружающие записи в потоке логов до и после совпавших записей (аналогично grep -A / grep -B). Возвращаемые блоки разделяются сообщением --- для удобства исследования.

Например, до 10 записей после каждого сообщения со словом panic за последние 5 минут:

_time:5m panic | stream_context after 10

До 5 записей перед каждым сообщением со словом stacktrace:

_time:5m stacktrace | stream_context before 5

До 2 записей перед и до 5 после сообщения со словом error:

_time:5m error | stream_context before 2 after 5

По умолчанию stream_context ищет окружающие записи в окне длительностью 1 час. Окно можно изменить через параметр time_window:

_time:5m error | stream_context before 10 time_window 1w

Пайп | stream_context должен идти первым сразу после фильтров.

См. также:


time_add pipe

<q> | time_add <duration> — пайп, добавляющий указанную длительность к полю _time.

Например, добавление одного часа к _time:

_time:5m | time_add 1h

Для вычитания укажите отрицательную длительность:

_time:5m | time_add -1h

Для применения к другому полю добавьте at <field_name>. Например, добавление одной недели к полю transaction_time:

_time:5m | time_add 1w at transaction_time

См. также:


top pipe

<q> | top N by (field1, ..., fieldN) — пайп, возвращающий топ N наборов полей с наибольшим количеством совпадающих записей.

Например, топ-7 потоков логов с наибольшим количеством записей за последние 5 минут (количество возвращается в поле hits):

_time:5m | top 7 by (_stream)

N необязателен — по умолчанию возвращается 10 записей:

_time:5m | top by (ip)

Можно переименовать поле hits:

_time:5m | top by (path) hits as visits

Можно добавить поле rank:

_time:5m | top 10 by (ip) rank

Поле rank может иметь другое имя:

_time:5m | top 10 by (ip) rank as position

См. также:


total_stats pipe

<q> | total_stats ... — пайп, вычисляющий глобальную (итоговую) статистику по указанным полям и сохраняющий результат в каждой входной записи.

Пайп total_stats сортирует логи по полю _time внутри каждой группы by(...) перед вычислением статистик. Если <q> не возвращает _time, порядок вывода не определён.

Пайп total_stats хранит все логи в памяти (до определённого лимита), поэтому убедитесь, что <q> возвращает ограниченное количество записей.

Например, глобальная сумма поля hits за последние 5 минут:

_time:5m | total_stats sum(hits) as total_hits

Базовый формат:

... | total_stats
  stats_func1(...) as result_name1,
  ...
  stats_funcN(...) as result_nameN

Например, вычисление глобального счётчика и суммы hits:

_time:5m
    | total_stats
        count() as total_logs,
        sum(hits) as total_hits

Имя результата можно опустить:

_time:5m | total_stats count(), sum(hits)

Полезно комбинировать с временными интервалами. Например, почасовое количество за последний день плюс итоговое значение и процент:

_time:1d
    | stats by (_time:hour) count() as hits
    | total_stats sum(hits) as total_hits
    | math round((hits / total_hits)*100) as hits_percent

Поддерживаемые функции total_stats:

  • count() — общее количество записей. Поддерживает count(fieldName), count(field1, field2) и count(prefix*).
  • max(field1, ..., fieldN) — глобальный максимум. Поддерживает max(prefix*).
  • min(field1, ..., fieldN) — глобальный минимум. Поддерживает min(prefix*).
  • sum(field1, ..., fieldN) — глобальная сумма числовых значений. Поддерживает sum(prefix*).

См. также:

total_stats по полям

Для вычисления независимой глобальной статистики для каждой группы полей:

<q> | total_stats by (field1, ..., fieldM)
  stats_func1(...) as result_name1,
  ...
  stats_funcN(...) as result_nameN

Например, глобальное количество логов и сумма hits, сгруппированные по (host, path):

_time:5m
    | total_stats by (host, path)
        count() total_logs,
        sum(hits) total_hits

Ключевое слово by можно опустить:

_time:5m | total_stats (host, path) count() total_logs, sum(hits) total_hits

См. также:


union pipe

<q1> | union (<q2>) — пайп, возвращающий результаты запроса <q1>, за которыми следуют результаты запроса <q2>. Работает аналогично UNION ALL в SQL.

Например, логи со словом error за последние 5 минут плюс логи со словом panic за последний час:

_time:5m error | union (_time:1h panic)

См. также:


uniq pipe

<q> | uniq by (field1, ..., fieldN) — пайп, возвращающий уникальные значения указанных полей.

Например, уникальные значения поля ip за последние 5 минут:

_time:5m | uniq by (ip)

Можно указать несколько полей для получения всех уникальных комбинаций:

_time:5m | uniq by (host, path)

Уникальные записи возвращаются в произвольном порядке. Используйте sort для сортировки.

Добавьте with hits для получения количества совпадений для каждого значения:

_time:5m | uniq by (host) with hits

Для ограничения количества уникальных записей добавьте limit N (уменьшает потребление памяти):

_time:5m | uniq by (host, path) limit 100

Если лимит достигнут, возвращается произвольное подмножество значений. При использовании with hits все значения hits устанавливаются в 0.

Ключевое слово by можно опустить:

_time:5m | uniq (host, path) limit 100

См. также:


unpack_json pipe

<q> | unpack_json from field_name — пайп, распаковывающий JSON вида {"k1":"v1", ..., "kN":"vN"} из указанного поля в выходные поля k1, …, kN с соответствующими значениями. Перезаписывает существующие поля с совпадающими именами.

Вложенный JSON распаковывается согласно модели данных платформы. Для сохранения значений определённых JSON-ключей от разворачивания перечислите их в preserve_keys (...):

_time:5m | unpack_json from _msg preserve_keys (foo, bar)

Часть from _msg можно опустить:

_time:5m | unpack_json

Для извлечения только определённых полей перечислите их в fields (...):

_time:5m | unpack_json from my_json fields (foo, bar)

Для извлечения полей с общим префиксом используйте fields(prefix*).

Для сохранения оригинальных непустых значений добавьте keep_original_fields:

_time:5m | unpack_json from foo fields (ip, host) keep_original_fields

Для сохранения оригинальных значений при пустых распакованных добавьте skip_empty_results:

_time:5m | unpack_json fields (ip, host) skip_empty_results

Совет по производительности: если нужно извлечь одно поле из длинного JSON, пайп extract будет быстрее:

_time:5m | extract '"ip":<ip>'

Для добавления общего префикса к распакованным полям используйте result_prefix:

_time:5m | unpack_json from foo result_prefix "foo_"

Советы по производительности:

  • С точки зрения производительности лучше принимать уже разобранные JSON-логи в хранилище логов, чем парсить их на этапе запроса.
  • Рекомендуется использовать более специфичные фильтры для уменьшения количества записей, передаваемых в unpack_json.

См. также:

Условный unpack_json

Если пайп unpack_json должен применяться только к некоторым записям, добавьте if (<filters>) после unpack_json. Например, распаковка JSON из поля foo только если поле ip отсутствует или пусто:

_time:5m | unpack_json if (ip:"") from foo

unpack_logfmt pipe

<q> | unpack_logfmt from field_name — пайп, распаковывающий поля формата logfmt (k1=v1 ... kN=vN) из указанного поля в выходные поля k1, …, kN.

Например, распаковка logfmt из поля _msg за последние 5 минут:

_time:5m | unpack_logfmt from _msg

Часть from _msg можно опустить:

_time:5m | unpack_logfmt

Для извлечения только определённых полей:

_time:5m | unpack_logfmt from my_logfmt fields (foo, bar)

Для извлечения полей с общим префиксом используйте fields(prefix*).

Для сохранения оригинальных непустых значений:

_time:5m | unpack_logfmt from foo fields (ip, host) keep_original_fields

Для сохранения оригинальных значений при пустых распакованных:

_time:5m | unpack_logfmt fields (ip, host) skip_empty_results

Совет по производительности: для извлечения одного поля из длинной logfmt-строки пайп extract будет быстрее:

_time:5m | extract ' ip=<ip>'

Для добавления общего префикса к распакованным полям:

_time:5m | unpack_logfmt from foo result_prefix "foo_"

Советы по производительности:

  • Лучше принимать уже разобранные logfmt-логи в хранилище логов, чем парсить их при запросе.
  • Рекомендуется использовать более специфичные фильтры для уменьшения количества записей, передаваемых в unpack_logfmt.

См. также:

Условный unpack_logfmt

Если пайп unpack_logfmt должен применяться только к некоторым записям, добавьте if (<filters>) после unpack_logfmt. Например, распаковка logfmt из поля foo только если поле ip отсутствует или пусто:

_time:5m | unpack_logfmt if (ip:"") from foo

unpack_syslog pipe

<q> | unpack_syslog from field_name — пайп, распаковывающий syslog-сообщения из указанного поля. Поддерживаемые форматы:

  • RFC3164: <PRI>MMM DD hh:mm:ss HOSTNAME APP-NAME[PROCID]: MESSAGE
  • RFC5424: <PRI>1 TIMESTAMP HOSTNAME APP-NAME PROCID MSGID [STRUCTURED-DATA] MESSAGE

Распаковываются следующие поля:

  • level — получено из PRI
  • priority — получено из PRI
  • facility — вычисляется как PRI / 8
  • facility_keyword — строковое представление facility
  • severity — вычисляется как PRI % 8
  • formatrfc3164 или rfc5424
  • timestamp — метка времени в формате ISO8601. Метка времени RFC3164 (MMM DD hh:mm:ss) автоматически конвертируется в ISO8601 с использованием текущего года
  • hostname
  • app_name
  • proc_id
  • msg_id
  • message

Часть <PRI> необязательна. [STRUCTURED-DATA] парсится в поля вида SD-ID.param1, …, SD-ID.paramN.

Если app_name равно CEF и message содержит данные Common Event Format, они автоматически парсятся в поля:

  • cef.version, cef.device_vendor, cef.device_product, cef.device_version, cef.device_event_class_id, cef.name, cef.severity
  • Расширения парсятся в cef.extension.<key>

Пример распаковки syslog из поля _msg:

_time:5m | unpack_syslog from _msg

Часть from _msg можно опустить:

_time:5m | unpack_syslog

По умолчанию метки времени RFC3164 интерпретируются в локальном часовом поясе. Смещение можно изменить через offset:

_time:5m | unpack_syslog offset 5h30m

Для сохранения оригинальных непустых значений:

_time:5m | unpack_syslog keep_original_fields

Для добавления общего префикса к распакованным полям:

_time:5m | unpack_syslog from foo result_prefix "foo_"

Советы по производительности:

  • Лучше принимать уже разобранные syslog-сообщения в хранилище логов, чем парсить их при запросе.
  • Рекомендуется использовать более специфичные фильтры для уменьшения количества записей, передаваемых в unpack_syslog.

См. также:

Условный unpack_syslog

Если пайп unpack_syslog должен применяться только к некоторым записям, добавьте if (<filters>) после unpack_syslog. Например, распаковка syslog из поля foo только если поле hostname отсутствует или пусто:

_time:5m | unpack_syslog if (hostname:"") from foo

unpack_words pipe

<q> | unpack_words from <src_field> as <dst_field> — пайп, извлекающий слова из указанного поля и сохраняющий их как JSON-массив в целевое поле.

Например, извлечение слов из сообщений в поле words:

_time:5m | unpack_words from _msg as words

Часть as <dst_field> необязательна — если опущена, результат сохраняется в исходное поле:

_time:5m | unpack_words from _msg

Часть from <src_field> необязательна — если опущена, слова извлекаются из _msg:

_time:5m | unpack_words

По умолчанию извлекаются все слова, включая дубликаты. Для удаления дубликатов добавьте drop_duplicates:

_time:5m | unpack_words from text as words drop_duplicates

Удобно использовать unroll для развёртывания JSON-массива. Например, топ-5 наиболее частых слов:

_time:5m | unpack_words as words | unroll words | top 5 (words)

См. также:


unroll pipe

<q> | unroll [by] (field1, ..., fieldN) — пайп, разворачивающий JSON-массивы из указанных полей в отдельные строки.

Например, развёртывание полей timestamp и value:

_time:5m | unroll (timestamp, value)

Ключевое слово by можно опустить. Если разворачивается несколько полей, наиболее длинный JSON-массив определяет количество строк, а недостающие элементы для более коротких массивов заполняются пустыми строками.

Если развёрнутый JSON-массив содержит JSON-объекты, удобно использовать unpack_json для распаковки элементов в отдельные поля.

См. также:

Условный unroll

Если пайп unroll должен применяться только к некоторым записям, добавьте if (<filters>) после unroll. Например, развёртывание поля value только если value_type равно json_array:

_time:5m | unroll if (value_type:="json_array") (value)

Навигация