Парсинг логов с grok
Главный инструмент превращения сырой строки в структуру — фильтр grok и его язык шаблонов.
grok — фильтр, который сопоставляет строку лога с шаблоном из именованных кусочков-регулярок и извлекает совпавшие части в отдельные поля.
Проблема, которую решает grok
Логи многих сервисов — это неструктурированный текст. Строка лога nginx выглядит так:
192.168.1.10 - - [24/Jun/2026:14:32:07 +0000] "GET /api/orders HTTP/1.1" 500 234Для человека читаемо, для машины — мусор: это одно поле message, по которому нельзя ни отфильтровать по status: 500, ни построить график ошибок по path. grok разбирает её на поля.
Анатомия grok-шаблона
Базовый синтаксис — %{ШАБЛОН:имя_поля}. ШАБЛОН — это готовая именованная регулярка (например, IP, NUMBER, WORD), имя_поля — куда положить результат. Разберём ту же строку nginx вручную:
filter {
grok {
match => { "message" => "%{IPORHOST:client_ip} - - \[%{HTTPDATE:timestamp}\] \"%{WORD:method} %{URIPATHPARAM:path} HTTP/%{NUMBER:http_version}\" %{NUMBER:status:int} %{NUMBER:bytes:int}" }
}
}Результат — структурированный документ:
{
"client_ip": "192.168.1.10",
"method": "GET",
"path": "/api/orders",
"status": 500,
"bytes": 234
}Обратите внимание на %{NUMBER:status:int} — третий сегмент :int приводит поле к числу, иначе status будет строкой и по нему нельзя считать числовые агрегаты.
Готовые шаблоны
Писать всё с нуля не нужно: Logstash несёт сотни готовых паттернов, и для типовых форматов есть составные. Тот же лог nginx целиком покрывается одним %{COMBINEDAPACHELOG}. Полезные базовые шаблоны:
| Шаблон | Что ловит |
%{IP} | IP-адрес |
%{NUMBER} | число |
%{WORD} | слово без пробелов |
%{HTTPDATE} | дата в формате логов Apache |
%{LOGLEVEL} | уровень (INFO, ERROR...) |
%{GREEDYDATA} | «всё остальное» до конца строки |
Как работает под капотом
Под капотом grok — это просто регулярные выражения. Каждый %{ШАБЛОН} разворачивается в кусок regex, шаблоны вкладываются друг в друга (COMBINEDAPACHELOG состоит из десятка мелких), и итоговая большая регулярка применяется к строке. Отсюда и главная слабость: grok может быть медленным и «прожорливым» на сложных строках, потому что движок regex перебирает варианты с откатами (backtracking).
Отладка grok
Составить рабочий grok с первого раза почти никогда не выходит. В Kibana есть Grok Debugger (Dev Tools → Grok Debugger): вставляете образец строки, пишете шаблон и сразу видите, что извлеклось, а что нет. Это незаменимый инструмент — отлаживайте шаблон там, а не методом «поправил конфиг → перезапустил Logstash → посмотрел». Если строка не совпала с шаблоном, Logstash вешает на событие тег _grokparsefailure — по нему легко найти все строки, которые не распарсились.
Grok Debugger:
+---------------------------+
| образец: 192.168.1.10 ... |
| шаблон: %{IP:client_ip}..|
+---------------------------+
| результат: { client_ip:.. } | -- видно сразу
+---------------------------+Стратегия построения шаблона
Хороший рабочий процесс с grok выглядит так. Сначала возьмите несколько разных образцов строк лога, а не одну — форматы часто варьируются (есть строки с дополнительным полем, есть с пустыми значениями). Затем стройте шаблон от крупного к мелкому: сперва опишите общую структуру составными шаблонами, и только если их не хватает — спускайтесь к мелким WORD, DATA. Завершайте строку шаблоном GREEDYDATA для «хвоста», чтобы видеть, что осталось неразобранным, — это помогает не потерять данные молча. И обязательно прогоните на всех образцах в Grok Debugger: шаблон, идеально совпавший с одной строкой, нередко спотыкается на соседней с чуть иным форматом.
Важно также понимать DATA против GREEDYDATA. Первый — «нежадный», берёт минимум символов до следующего якоря в шаблоне; второй — «жадный», хватает всё до конца. Неправильный выбор между ними — частая причина, почему grok извлекает не то: жадный шаблон в середине строки «съедает» поля, которые вы хотели разобрать отдельно. Осознанное чередование жадных и нежадных кусков — половина искусства написания grok. А если grok оказывается слишком медленным или хрупким, это нередко сигнал, что пора не оттачивать регулярку, а перейти к структурированному логированию из следующего раздела — лучший grok тот, которого нет.
Частые ошибки
- Забыть :int / :float. Числа без приведения типа индексируются как строки — агрегации и сравнения
status >= 500не работают. - Злоупотреблять GREEDYDATA. Жадный
%{GREEDYDATA}в середине шаблона провоцирует катастрофический backtracking и тормозит весь Logstash. - Игнорировать _grokparsefailure. Если формат лога чуть изменился, шаблон молча перестаёт совпадать. Мониторьте тег
_grokparsefailure, чтобы ловить это.
Итоги
- grok превращает неструктурированную строку лога в поля через шаблоны вида
%{ШАБЛОН:имя}. - Суффикс
:int/:floatприводит поле к числу — без него не будет числовых агрегаций. - Под капотом grok — это вложенные регулярки; жадные шаблоны опасны замедлением.
- Отлаживайте в Kibana Grok Debugger и следите за тегом
_grokparsefailure.