Структурированное логирование: JSON вместо grok
Лучший grok — это его отсутствие: если приложение пишет логи сразу в JSON, парсить нечего.
Структурированное логирование — практика, при которой приложение пишет каждое событие сразу в машиночитаемом формате (обычно JSON) с уже выделенными полями, а не как человекочитаемую строку.
Корень проблемы grok
Весь предыдущий раздел мы учились распутывать текстовые логи регулярками. Но задумайтесь: приложение сначала взяло структурированные данные (объект ошибки, id заказа, статус) и склеило их в строку "payment failed for order 8842: timeout". А потом мы героически разбираем эту строку обратно на поля grok'ом. Это лишняя работа в обе стороны, и она хрупкая: чуть изменился формат строки — grok сломался.
Решение: писать сразу JSON
Если приложение логирует структурированно, событие уже приходит готовым:
{
"@timestamp": "2026-06-24T14:32:07Z",
"level": "ERROR",
"service": "billing",
"message": "payment failed",
"order_id": 8842,
"reason": "gateway timeout",
"trace_id": "a1b2c3d4"
}Здесь нечего парсить: order_id уже число, level уже отдельное поле, trace_id на месте. Filebeat прочитает строку, а разбор — это тривиальный JSON-декодер, а не хрупкая регулярка.
Как включить
В большинстве языков есть логгеры для JSON-вывода: structlog или python-json-logger в Python, Logback с JSON-энкодером в Java, pino/winston в Node, zap в Go. На стороне сбора JSON разбирается одной строкой — либо в Filebeat (parsers: - ndjson), либо фильтром Logstash:
filter {
json {
source => "message"
}
}Почему это лучше: ECS и единый стандарт
Elastic продвигает ECS (Elastic Common Schema) — стандарт имён полей: source.ip, http.response.status_code, service.name, log.level. Когда все сервисы пишут JSON по ECS, поля во всех логах называются одинаково. Тогда один дашборд «ошибки по сервисам» работает сразу для всех, а не требует подгонки под каждый формат. Это и есть переход от «каждый сервис логирует как хочет» к единому языку логов в компании.
Как работает под капотом: где экономия
Сравним два пути обработки одной ошибки:
ТЕКСТ + grok:
объект --склейка--> строка --grok(regex+backtracking)--> поля
(в приложении) (дорого, хрупко, в Logstash)
СТРУКТУРИРОВАННО (JSON):
объект --JSON-encode--> строка --JSON-decode--> поля
(в приложении) (дёшево, надёжно)JSON-декодирование на порядок дешевле grok-регулярки и не ломается от перестановки слов в сообщении. На больших объёмах это заметная экономия CPU на узлах обработки и отсутствие класса проблем «логи перестали парситься после релиза».
Что считать хорошим набором полей
Перейдя на структурированные логи, команда сталкивается с новым вопросом: какие именно поля логировать? Полезный базовый набор для каждого события: точное время (@timestamp), уровень (log.level), имя сервиса и его версия (service.name, service.version), идентификатор для корреляции (trace_id), краткое человекочитаемое сообщение (message) и — для ошибок — тип исключения и стектрейс в отдельных полях. К этому добавляют доменный контекст события: для веб-запроса это метод, путь, статус, длительность; для фоновой задачи — её имя и параметры. Ключевой принцип — контекст кладут в отдельные поля, а не зашивают в текст message, иначе теряется весь смысл структурирования.
Есть и тонкость с самим полем message. В структурированном мире оно должно быть стабильным шаблоном без переменных частей: не «user 8842 logged in», а message со значением «user logged in» плюс отдельное поле user_id со значением 8842. Стабильное сообщение позволяет агрегировать одинаковые по смыслу события вместе («сколько раз был тип события user logged in»), тогда как сообщение с вкраплённым id уникально для каждого случая и не группируется. Это маленькое правило радикально повышает аналитическую ценность логов.
Частые ошибки
- Взрыв полей через JSON. Свобода JSON опасна: если логировать произвольные ключи (например,
user_42_action), Elasticsearch заведёт новое поле под каждый — это «mapping explosion». Держите набор ключей фиксированным. - Дублировать @timestamp и message. Если в JSON есть свои
@timestamp/message, согласуйте их с тем, что добавляет Filebeat, иначе будет путаница полей. - Логировать секреты. Структурированный лог легко превращается в утечку: пароль или токен в поле JSON попадёт в индекс. Маскируйте чувствительные поля до отправки.
Итоги
- Структурированное (JSON) логирование избавляет от хрупкого grok: поля приходят готовыми.
- JSON-декодирование дешевле и надёжнее регулярок и не ломается от смены формата строки.
- Единый стандарт имён полей (ECS) делает дашборды переносимыми между всеми сервисами.
- Осторожно с произвольными ключами (взрыв полей) и секретами в логах.