Как добавлять логи в Elasticsearch с помощью Logstash

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

Logstash - это инструмент, который принимает на вход логи в различных форматах, обрабатывает их и отправляет на индексацию Elasticsearch.

Чтобы после установки Logstash провести эксперимент по заливке данных в Elasticsearch, необходимы данные в больших объемах. К счастью, у каждого пользователя Linux есть логи в больших количествах - в директории /var/log/ . Вот их и будем индексировать.

Обработка данных в Logstash организована по принципу конвейера и осуществляется с помощью плагинов. Любая информация проходит последовательно через цепочку плагинов. Конвееры Logstash создаются на основе одного или нескольких файлов конфигурации.

Плагины группируются по своему предназначению:

  • input - входные плагины, отвечают за прием данных и отправку их в очередь на обработку;
  • filter - фильтры, преобразуют данные, разбивают их на части;
  • output - выходные плагины, отвечают за форматирование и доставку данных адресату (не обязательно Elasticsearch).

Logstash поставляется с большим набором плагинов.

Изображение взято отсюда: www.elastic.co/blog/a-practical-introduction-to-logstash

Для обработки нового лога требуется создать новый конфигурационный файл и определить - какие плагины на каком этапе необходимо использовать.

Заготовка конфигурационного файла:

Любая конфигурация Logstash должна определять как минимум один входной плагин и один выходной. Фильтры не являются обязательными.

Конфигурация Logstash для вывода данных в файл

Для обработки я выбрала файл /var/log/vsftpd.log. Неприятной особенностью данного лога является разное содержимое и формат каждой строки:

В директории /etc/logstash/conf.d/ создаем файл test.conf:

Благодаря приведенному конфигу, Logstash прочитает данные из файла /var/log/vsftpd.log, разобьет каждую строку на пары "ключ"/"значение", и запишет получившиеся структуры данных в json-формате, в файл /home/apache/output_logstash.log .

Почему запись сделана не в Elasticsearch, а в простой текстовый файл? Потому, что так удобнее на этапе отладки блока filter. Составить удовлетворяющие шаблоны для парсинга строк лога может получится далеко не сразу. Удалить данные из текстового файла и запустить парсинг заново намного проще, чем почистить Elasticsearch.

Запускаем Logstash:

После этого есть время на то, чтоб приготовить чашечку кофе - Logstash требуется время на запуск.

Открываем файл /home/apache/output_logstash.log:

Останавливаем Logstash:

Конфигурация Logstash для отправки данных в Elasticsearch

Допустим, получившаяся структура данных нас устраивает и ошибок парсинга не случилось. Теперь изменим в конфиге /etc/logstash/conf.d/test.conf блок output:

Запускаем все необходимые сервисы:

Позволяем этим сервисам загрузиться, ждем некоторое время. Запускаем Logstash. После того, как Logstash загрузится, он распарсит данные по уже отлаженному нами шаблону, но запишет результат не в файл, а передаст на индексацию Elasticsearch.

В браузере вводим адрес http://localhost:9999/app/kibana . Переходим на страницу "Management". Далее пункты меню "Kibana" -> "Index Patterns" и нажимаем кнопку "Refresh field list".

Обновление полей индекса Elasticsearch в Kibana

Обновление полей индекса Elasticsearch в Kibana

Теперь можно попробовать просмотреть результаты работы Logstash. Переходим на страницу "Discover":

Просмотр содержимого индекса Elasticsearch с помощью Kibana

Просмотр содержимого индекса Elasticsearch с помощью Kibana

Если Kibana пишет, что никаких данных не найдено ("No results match your search criteria"), попробуйте изменить временной интервал, указанный в правом верхнем углу страницы. По умолчанию, Kibana показывает данные, которые были добавлены за последние 15 минут.

Разворачиваем данные для просмотра:

Просмотр содержимого индекса Elasticsearch в Kibana

Просмотр содержимого индекса Elasticsearch в Kibana

Дополнительные комментарии к конфигурационному файлу Logstash

Конфигурирование блока input

Input-плагин позволяет Logstash прочитать данные из определенного источника. В указанном примере, данные запрашиваются из файла /var/log/vsftpd.log и используется плагин "file".

Деректива start_position, возможные значения: beginning, end (по умолчанию). Определяет, с какой позиции читать данные при обнаружении нового файла, с начала или с конца. Если мы работаем со старыми данными, устанавливаем "beginning". Если в режиме реального времени отслеживаем добавление новых данных в файл - то "end". Директива имеет значение только при самом первом обнаружении файла. При каждом прохождении Logstash начнет сохранять текущую позицию в файле sincedb, и в дальнейшем начинать просмотр именно с нее.

Директива sincedb_path - путь к файлу базы данных sincedb. Logstash использует sincedb для записи информации о текущей позиции читаемого файла. Т.к. при отладке конфига нам требуется многократное прохождение одного и того же файла, предлагаем Logstash писать данные о текущей позиции в /dev/null.

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

  • beats - позволяет получать данные, отправленные агентами Elastic Beats;
  • file - читает данные из файла;
  • rabbitmq - получает данные от RabbitMQ exchange;
  • redis - читает данные из Redis;
  • sqlite - получает данные из базы данных SQLite;
  • syslog - прослушивает порт 514 на предмет появления новых сообщений syslog и анализирует их в соответствии со стандартом RFC3164;
  • twitter - читает данные из Twitter Streaming API.

elastic.co: Полный список Input-плагинов для текущей версии Logstash. Там же ссылки на параметры настройки каждого плагина.

Конфигурирование блока fliter

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

Использование фильтра dissect

Фильтр Dissect - это своеобразная операция "split". Отличается тем, что в обычных "split"-функциях - указывается один разделитель, который применяется ко всей строке, а Dissect - задает шаблон строки с разделителями и набором полей. Dissect не использует регулярные выражения, работает быстро. Если текст от строки к строке слишком отличается, возможно, стоит использовать другой фильтр - Grok. Возможно так же комбинированое использование: сначала к строке применяется Dissect, затем Grok.

Директива mapping - содержит список полей "ключ"/"значение", где ключ - это название поля, содержимое которого предлагается разбить на части, а значение - это шаблон, по которому это будет выполняться.

Разбиение строки выполняется слева направо. Выполняется с помощью специальных %{} блоков. Внутри блока указывается имя будущего поля. Все, что находится между блоками %{} - будет являться разделителями.

При разборе строки текст захватывается до первого разделителя - этот захваченный текст сохраняется в первом поле. Операция повторяется для каждой пары "блок %{}"-"разделитель" до тех пор, пока не будет достигнут последний разделитель. Оставшийся текст будет сохранен в последнем поле, заданном с помощью %{}.

Для разбора строки из лога:

использовался следующий шаблон:

Первый разделитель - одиночный пробел, все символы, которые встретятся до первого попавшегося одиночного пробела будут выделены в поле с именем day_name. Следующий разделитель - тройной пробел, все символы, которые будут найдены в промежутке между одиночным пробелом и тройным - будут выделены в отдельное поле под названием "month_name", и так далее. Последним разделителем в данном шаблоне является сочетание символов ": ", весь найденный текст после этого разделителя будет помещен в поле с именем %{msg}. Кстати, после того, как поля выделены и содержат значения, их можно снова пропустить через какой-нибудь фильтр для дополнительной обработки - я так и сделала для поля "type".

Блоки %{} могут содержать специальные префиксы перед именем поля: "?", "+", "&" или суффикс "/num".

  • %{} - пустое поле, пропускаем, сохранять не требуется. Формат шаблона требует, чтоб был указан каждый разделитель, но что если в строке встречается переменное значение, которое нельзя указать заранее?
  • %{?foo} - именованное поле.
  • %{field_name1} %{+field_name1} - "+field_name1" значение этого поля добавляется к значению уже существующего поля "field_name1"
  • Модификатор /digits позволяет изменить порядок добавления значения к полю. Например, для текста "1 2 3 go", применим шаблон "%{+a/2} %{+a/1} %{+a/4} %{+a/3}" и получим ключ с именем "a" и значением "2 1 go 3". Если модификатор порядка не использовался, значения будут добавляться в порядке нахождения.
  • %{&some_field} - позволяет использовать в качестве имени ключа значение другого поля. Например, для текста "error: some_error, some_description" применим шаблон "error: %{?err}, %{&err}" и получим пару "ключ"/"значение": "some_error" => "some_description".

Самые интересные фильтры Logstash:

  • dissect - разбирает текст и превращает его в структуру данных, работает по принципу "split";
  • drop - позволяет полностью удалить событие, структуру данных. Может быть полезно для удаления отладочных сообщений;
  • grok - разбирает текст и превращает его в структуру данных, работает по принципу регулярных выражений;
  • mutate - выполняет преобразования в полях структур данных, позволяет переименовывать поля, удалять, заменять и изменять их.

elastic.co: Полный список Filter-плагинов для текущей версии Logstash

github.com: Список доступных паттернов для grok

Конфигурирование блока output

Output-плагин отправляет обработанные данные в конкретный пункт назначения. Это завершающий этап в конвеере Logstash.

В приведенном примере используется плагин для вывода данных в файл. Директива codec - определяет, в каком формате сохранить данные.

elastic.co: Полный список кодеков для определения формата вывода данных

Список самых полезных доступных Output-плагинов:

  • csv - сохраняет данные на диск в формате csv;
  • elasticsearch - отправляет данные Elasticsearch;
  • email - отправляет письмо на указанный адрес электронной почты;
  • file - пишет информацию в файл;
  • nagios - отправляет результаты пассивной проверки в Nagios;
  • redmine - создает новый тикет с помощью Redmine API.

elastic.co: Полный список Output-плагинов для текущей версии Logstash