Обрабатываем логи в Logstash

Итак, с Elasticsearch, гибридом гугла и NoSQL базы данных, мы разобрались, самое время перейти к следующей букве ELK стэка от Elastic — Logstash.

Что такое Logstash

Logstash — это конвейер обработки данных, который получает сырые данные (например, логи) из одного или нескольких  источников, обрабатывает их и улучшает фильтрами, а затем отправляет результат одному или нескольким получателямElastic рекомендует в качестве получателя использовать Elasticsearch, но на самом деле можно использовать всё, что душе угодно: STDOUT, WebSocket, обычные сокеты, очереди сообщений — выбор огромный.

Установка

Если на хосте установлена Java, то можно просто скачать  архив, распаковать его и запустить bin/logstash -f logstash.conf. Для запуска, правда, понадобится файл конфигурации, но для простейших примеров сойдёт что-нибудь вроде input {STDIN {}} output {STDOUT {}}.

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

Конфигурация, кодеки и «Hello World!»

Итак, архив скачан, что дальше? Как я упомянул выше, для запуска Logstash нужен файл конфигурации. Например, такой:

С ним Logstash будет брать данные из консоли, делать свою магию по-умолчанию, и выдавать результат назад в консоль.

Hello world

Я нашёл у себя на хосте немного логов от Apache2, так что почему бы не скормить их Logstash и не посмотреть, что из этого получится?

А получится много скучного текста. Logstash запустился, ему на вход вошла строка (4) с логом от Apache2, и она тут же пошла на выход с двумя новыми полями: временной меткой 2017-02-13T05:39:12.684Z и именем хоста 269a27a16415.

Кодеки

Но мы можем сделать вывод более читабельным. Logstash разрешает подключать ко вводу и выводу различные кодеки, которые форматируют поток текста, но не меняют его значение: добавляют отступы, архивируют, переводят в JSON, и т. п. В нашем случае мы можем использовать rubydebug для того, чтобы он отформатировал результат и показал, как именно Logstash «видит» данные, с которыми работает.

Конфигурация изменится совсем чуть-чуть, но результат станет намного человечнее:

Выводим результаты в Elasticsearch

Прежде чем двинуться дальше, стоит попробовать кое-что еще. В начале поста я сказал, что получателей данных может быть больше одного, и вообще мы можем писать результаты прямо в Elasticsearch. Это как раз тот случай, когда можно одним телодвижением подтвердить оба пункта.

Так уж оказалось, что в соседнем с Logstash контейнером у меня обосновался чистый Elasticsearch с айпишкой 172.19.0.2 и портом 9200. Чтобы подключить их друг к другу, нужно добавить всего пару строк в конфигурацию Logstash:

Теперь, если перезапустить Logstash и снова скормить ему  Apache2 логов, в Elasticsearch появится кое что относительно интересное:

Во-первых, там появился новый индекс — logstash-2017.02.12. Во-вторых, запустив по этому индексу поиск, мы получим те же данные, что Logstash писал в STDOUT:

Обрабатываем данные фильтрами

Пока Logstash справлялся с переправкой логов из точки А в точку Б, но не делал ничего для того, чтобы это данные стали хоть немного полезнее. Пришло время перемен. Кроме INPUT и OUTPUT в конфигурацию можно добавить FILTER, и вот там-то основная магия и начнётся.

Фильтры есть практически для всего: для агрегации метрик, маскировки чувствительных данных (вроде имён и номеров кредитных карт), добавления и удаления полей, нахождения IP по доменному имени, нахождения адреса по IP (держитесь, комментаторы!), и т.п. Но для нас хорошо бы начать с разбора строки Apache2 лога на её компоненты: IP, путь, user agent, и так далее. Фильтр, который занимается подобной работой, называется grok.

Grok

Grok — это основной инструмент для придания формы и структуры сполшному массиву текста. Работает это так: из предустановленных паттернов (IP, Number, Word, …) мы собираем строку-шаблон, которая по структуре повторяет ту, которую мы собираемся парсить. Например, если бы мои логи выглядели так:

То я бы использовал такой шаблон для их разбора:

После обработки фильтром в логах появились бы новые поля: sequenceclient и target. Те самые, которые указали в шаблоне.

Кроме элементарных паттернов вроде Number есть более сложные, которые описывают известные форматы логов целиком. Например, COMBINEDAPACHELOG описывает строку лога от Apache2. Вот её-то и можно попробовать в действии.

Новая конфигурация:

И реакция Logstash на неё:

Сработало!

Дополнительные настройки GROK

Но обработку можно сделать еще лучше. В середине распаршеного лога затесалось поле message, которое дублирует всё, что мы только что распарсили. Хорошо бы его убрать. А в grok как раз есть дополнитальные настройки, одна из которых называется remove_field — как раз то, что нам нужно:

Теперь результат просто прекрасен. Но мы можем сделать его ещё лучше.

geoip фильтр

Как следует из названия, geoip конвертирует IP адрес в координаты на карте и сопутствующий уличный адрес. Я заменил докеровскую айпишку одного из логов на свою внешнюю, включил geoip, и пропустил лог через Logstash еще раз:

Ну разве это не прекрасно? Разве что телефона там моего нет:

geoip взял clientip поле, которое создал grok, и потом добавил несколько собственных полей. Мне даже не пришлось что-то выкачивать из ваших интернетов, чтобы это заработало.

А теперь, когда обработанные данные стекаются в Elasticsearch, мы можем использовать его поиск на полную катушку и начать задавать вопросы. Были ли посетители из Oakville?

Конечно были. А сколько HTTP ошибок было вчера? Пытался ли кто-нибудь зайти в админку блога без спроса? Сколько раз? Где он живёт?

Можно задавать много, много вопросов.

Итог

Logstash принадлежит к классу инструментов, которые не создают особого впечатления своим описанием, но немного влюбляют в себя после того, как с ними поиграешься. Стоит немного покомбинировать входы, выходы и фильтры, как становится дико интересно, что же ещё можно выцедить из своих данных.

Да, Logstash прекрасно работает с Elasticsearch, но и источниками и получателями данных может быть огромный набор сервисов, начиная с очередей сообщений и заканчивая TCP сокетами.

Но в этой картине вселенского счастья пропущен один элемент — пользовательский интерфейс. Что ни говори, анализировать логи из командной строки — не самое продуктивное занятие. Чтобы это исправить, в следующий раз мы посмотрим в сторону последнего компонента ELK стека — Kibana.