Grok разобрал строку nginx на поля. Но событие ещё сыровато: время в поле @timestamp это момент, когда строка дошла до Logstash, а не когда случился запрос; адрес клиента просто цифры; проверки здоровья засоряют индекс; исходная строка лежит дважды. Доведём событие до ума. Это называют обогащением.
Правильное время: date
Самая важная правка. Логи доезжают до Logstash с задержкой: секунды, минуты, а после сбоя сети и часы. Если оставить @timestamp временем прихода, график ошибок в Kibana покажет инцидент не там, где он был. Поэтому время берут из самой строки фильтром date:
date {
match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
}
Первым идёт поле со временем, дальше один или несколько форматов. dd/MMM/yyyy:HH:mm:ss Z описывает 30/Jun/2026:22:40:11 +0300: день, месяц тремя буквами, год, время и смещение пояса. Буквы взяты из Java: MMM это месяц словом, Z смещение вида +0300, SSS миллисекунды. Для времени в формате ISO 8601 есть готовое слово ISO8601.
Серверы «Гонца» пишут логи по московскому времени, а Elasticsearch хранит время в UTC. Фильтр date учтёт смещение +0300 и запишет 19:40:11 UTC. Если строка не разобралась, событие получит тег _dateparsefailure, а @timestamp останется прежним.
Порядок в полях: mutate
Mutate это набор мелких правок:
renameпереименовывает поле:{ "status" => "[http][response][status_code]" };convertприводит тип:{ "[upstream][response_time]" => "float" };remove_fieldудаляет лишнее;gsubзаменяет текст по регулярному выражению;lowercase,uppercase,stripчистят строки;add_fieldиadd_tagесть у любого фильтра.
Одна ловушка: внутри одного mutate операции выполняются не в том порядке, как записаны, а в фиксированном: сначала coerce и rename, потом update, replace, convert, gsub и так далее, а add_field и remove_field в самом конце. Если порядок важен, пиши несколько mutate подряд.
урок из курса
Урок из курса «Elasticsearch и ELK». Курс покупается один раз и остаётся навсегда: 500 ₽.
Оплата пока не подключена: премиум и курсы открываются промокодом.