Сбор и анализ логов с Fluentd

Любому системному администратору в своей повседневной деятельности приходится иметь дело со сбором и анализом логов. Собранные логи нужно хранить — они могут понадобиться для самых разных целей: для отладки программ, для разбора инцидентов, в качестве подспорья для службы техподдержки и т.п. Кроме того, необходимо обеспечить возможность поиска по всему массиву данных.

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

В течение последних нескольких лет появились интересные программные инструменты позволяющие решать описанные выше проблемы. Всё большую популярность обретают решения, позволяющие хранить и обрабатывать логи онлайн: Splunk,Loggly, Papertrail, Logentries и другие. В числе несомненных плюсов этих сервисов следует назвать удобный интерфейс и низкую стоимость использования (да и в рамках базовых бесплатных тарифов они предоставляют весьма неплохие возможности). Но по при работе с большими количествами логов они зачастую не справляются с возлагаемыми на них задачами. Кроме того, их использование для работы с большими количествами информации нередко оказывается невыгодным с чисто финансовой точки зрения.

Гораздо более предпочтительным вариантом является развёртывание самостоятельного решения. Мы задумались над этим вопросом, когда перед нами встала необходимось собирать и анализировать логи облачного хранилища.

Мы начали искать подходящее решение и остановили свой выбор на Fluentd — небезынтересном инструменте с достаточно широкой функциональностью, о котором почти нет подробных публикаций на русском языке. О возможностях Fluentd мы подробно расскажем в этой статье.

Общая информация

Fluend был разработан Садаюки Фурухаси, сооснователем компании Treasure Data(она является одним из спонсоров проекта), в 2011 году. Он написан на Ruby. Fluentd активно развивается и совершенствуется (см. репозиторий на GitHub, где обновления стабильно появляются раз в несколько дней).

В числе пользователей Fluentd — такие известные компании, как Nintendo, Amazon, Slideshare и другие.
Fluentd собирает логи из различных источников и передаёт их другим приложениям для дальнейшей обработки. В схематичном виде процесс сбора и анализа логов с помощью Fluentd можно представить так:

Fluentd

В качестве основных преимуществ Fluentd можно выделить следующие:

  • Низкие требования к системным ресурсам. Для нормальной работы Fluentd вполне достаточно 30 — 40 Мб оперативной памяти; скорость обработки при этом составляет 13 000 событий в секунду.
  • Использование унифицированного формата логгирования. Данные, полученные из разных источников, Fluentd переводит в формат JSON. Это помогает решить проблему сбора логов из различных систем и открывает широкие возможности для интеграции с другими программными решениями.
  • Удобная архитектура. Архитектура Fluentd позволяет расширять имеющийся набор функций с помощью многочисленных плагинов (на сегодняшний день их создано более 300). С помощью плагинов можно подключать новые источники данных и выводить данные в различных форматах.
  • Возможность интеграции с различными языками программирования. Fluentd может принимать логи из приложений на Python, Ruby, PHP, Perl, Node.JS, Java, Scala.

Fluentd распространяется бесплатно под лицензией Apache 2.0. Проект достаточно подробно документирован; на официальном сайте и в блоге опубликовано немало полезных обучающих материалов.

Установка

В рамках этой статьи мы описываем процедуру установки для ОС Ubuntu 14.04. С инструкциями по установке для других операционных систем можно ознакомиться здесь.

Установка и первоначальная настройка Fluentd осуществляются с помощью специального скрипта. Выполним команды:

$ wget http://packages.treasuredata.com/2/ubuntu/trusty/pool/contrib/t/td-agent/td-agent_2.0.4-0_amd64.deb

$ sudo dpkg -i td-agent_2.0.4-0_amd64.deb

По завершении установки запустим Fluentd:

$ /etc/init.d/td-agent restart

Конфигурирование

Принцип работы Fluentd заключается в следующем: он собирает данные из различных источников, проверяет на соответствие определённым критериям, а далее переправляет в указанные локации для хранения и дальнейшей обработки. Наглядно всё это можно представить в виде следующей схемы:

Fluentd

Настройки fluentd (какие данные и откуда брать, каким критериям они должны соответствовать, куда их переправлять) прописываются в конфигурационном файле /etc/td-agent/td-agent.conf, который строится из следующих блоков:

  • source — содержит информацию об источнике данных;
  • match — содержит информацию о том, куда нужно передавать полученные данные;
  • include — содержит информацию о типах файлов;
  • system — содержит настройки системы.

Рассмотрим структуру и содержание этих блоков более подробно.

Source: откуда брать данные

В блоке source содержится информация о том, откуда нужно брать данные. Fluentd может принимать данные из различных источников: это логи приложений на различных языках программирования (Python, PHP, Ruby, Scala, Go, Perl, Java), логи баз данных, логи с различных аппаратных устройств, данные утилит мониторинга…. С полным списком возможных источников данных можно ознакомиться здесь. Для подключение источников используются специализированные плагины.
В число стандартных плагинов вхoдят http (используется для приёма HTTP-сообщений) и forward (используется для приёма TCP-пакетов). Можно использовать оба этих плагина одновременно.
Пример:

# Принимаем события с порта 24224/tcp
<source>
  type forward
  port 24224
</source>

# http://this.host:9880/myapp.access?json={"event":"data"}
<source>
  type http
  port 9880
</source>

Как видно из приведённого примера, тип плагина указывается в директиве type, а номер порта — в директиве port.
Количество источников данных ничем не ограничено. Каждый источник данных описывается в отдельном блоке <source>.
Все события, принятые из источников, передаются маршрутизатору сообщений. Каждое событие имеет три атрибута: tag, time и record. На основании атрибута tag принимается решение о том, куда должны быть перенаправлены события (подробнее об этом пойдёт речь ниже). В атрибуте time указывается время (это делается автоматически), а в атрибуте record — данные в формате JSON.
Приведём пример описания события:

# generated by http://this.host:9880/myapp.access?json={"event":"data"}
tag: myapp.access
time: (current time)
record: {"event":"data"}

Match: что делать с данными

В секции Match указывается, по каком признаку будут отбираться события для последующей обработки. Для этого используются специализированные плагины.

К стандартным плагинам вывода относятся match и forward:

#  Получаем события с порта 24224
<source>
  type forward
  port 24224
</source>

# http://this.host:9880/myapp.access?json={"event":"data"}
<source>
  type http
  port 9880
</source>

#Берём события, помеченные тэгами "myapp.access" 
#и сохраняем их в файле/var/log/fluent/access.%Y-%m-%d
#данные можно разбивать на порции с помощью опции time_slice_format.

<match myapp.access>
  type file
  path /var/log/fluent/access
</match>

В приведённом фрагменте указано, что все события, отмеченные тэгами myapp и access, нужно сохранять в файле, путь к которому указывается в директиве path. Обратим внимание на то, что события, которые помимо тэгов myapp и access отмечены ещё и другими тэгами, в файл отправлены не будут.
Кратко рассмотрим особенности синтаксиса директивы match:

  • символ * означает соответствие любой части тэга (если указать <match a.*>, то a.b будет соответствовать заданному условию, а a.b.c — нет);
  • ** означает соответствие любому тэгу (если указать <match **>, то заданному условию будут соответствовать и a, и a.b., и a.b.c);
  • {x, y, z} означает соответствие по крайней мере одному из тэгов, указанных в фигурных скобках (если указать <match {a, b}>, то а и b будут соответствовать заданному условию, а с — нет);
  • фигурные скобки можно использоовать в сочетании с символами * и **, например: <match {a, b}. c.*> или <match {a.*, b}.c>*;
  • <match a b> означает соответствие тэгам a и b одновременно;
  • <match a.** b.*> означает соответствие тэгам a, a.b и a.b.c (первая часть) и b.d (вторая часть).

Fluentd проверяет события на соответствие тэгам в том порядке, в котором блоки match следуют друг за другом в конфигурационном файле. Сначала указываются соответствия частного характера, а затем — более общие соответствия. Если это правило нарушено, Fluentd корректно работать не будет. Так, фрагмент вида

<match **>
  type blackhole_plugin
</match>

<match myapp.access>
  type file
  path /var/log/fluent/access
</match>

содержит ошибку: сначала в нём указаны предельно общие совпадения (<match **> означает, что в файл нужно записывать события, отмеченные любым тэгом), а затем — частные. Допущенная ошибка приведёт к тому, что события с тэгами myapp и access записываться вообще не будут. Чтобы все работало так, как надо, фрагмент должен выглядеть так:

<match myapp.access>
  type file
  path /var/log/fluent/access
</match>

<match **>
  type blackhole_plugin
</match>

Include: объединяем конфигурационные файлы

Директивы можно импортировать из одного конфигурационного файла в другой и объединять. Эта операция осуществляется в блоке include:

include config.d/*.conf

В этой директиве можно указывать путь к одному или нескольким файлам с указанием маски или URL:

# абсолютный путь к файлу
include /path/to/config.conf

# можно указывать и относительный путь
include extra.conf

# маска
include config.d/*.conf

# http
include http://example.com/fluent.conf

System: устанавливаем дополнительные настройки

В блоке System можно установить дополнительные настройки, например, задать уровень логгирования (подробнее см. здесь), включить ии отключить опцию удаления повторяющихся записей из логов и т.п.

Поддерживаемые типы данных

Каждый плагин для Fluentd обладает определённым набором параметров. Каждый параметр в свою очередь ассоциируется с определенным типом данных.
Приведём список типов данных, которые поддерживаются в Fluentd:

  • string — строка;
  • integer — целое число;
  • float — число с плавающей точкой;
  • size — число байт; возможны следующие варианты записи:
    • <целое число>k — размер в килобайтах;
    • <целое число>g — размер в гигабайтах;
    • <целое число>t — размер терабайтах;
    • если никакой единицы измерения не указано, то значение в поле size будет воспринято как число байт.
  • time — время; возможны следующие варианты записи:
    • <целое число>s — время в секундах;
    • <целое число>m — время в минутах;
    • <целое число>h — время в часах;
    • <целое число>d — время в днях;
    • если никакой единицы измерения не указано, что значение в поле time будет воспринято как количество секунд.
  • array — массив JSON;
  • hash — объект JSON.

Плагины Fluentd: расширяем возможности

В Fluentd используется 5 типов плагинов: плагины вывода, плагины ввода, плагины буферизации, плагины форм и плагины парсинга.

Плагины ввода

Плагины ввода используются для получения догов из внешних источников. Обычно такой плагин создает потоковый сокет (thread socket) и прослушивающий сокет (listen socket). Можно также настроить плагин так, что он будет получен данные из внешнего источника с определённой периодичностью.
К плагинам ввода относятся:

  • in_forward — прослушивает TCP-сокет;
  • in_http — принимает сообщения, передаваемые в POST-запросах;
  • in_tail — считывает сообщения, записанные в последних строках текстовых файлов (работает так же, как команда tail -F);
  • in_exec — с помощью этого плагина можно запускать стороннюю программу и получать её лог событий; поддерживаются форматы JSON, TSV и MessagePack;
  • in_syslog — с помощью этого плагина можно принимать сообщения в формате syslog по протоколу UDP;
  • in_scribe — позволяет получает сообщения в формате Scribe (Scribe — это тоже коллектор логов, разработанный Facebook).

Плагины вывода

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

  • плагины без буферизации — не сохраняют результаты в буфере и моментально пишут их в стандартный вывод;
  • с буферизацией — делят события на группы и записывают поочередно; можно устанавливать лимиты на количество хранимых событий, а также на количество событий, помещаемых в очередь;
  • с разделением по временным интервалам — эти плагины по сути являются разновидностью плагинов с буферизацией, только события делятся на группы по временным интервалам.

К плагинам без буферизации относятся:

  • out_copy — копирует события в указанное место (или несколько мест);
  • out_null — этот плагин просто выбрасывает пакеты;
  • out_roundrobin — записывает события в различные локации вывода, которые выбираются методом кругового перебора;
  • out_stdout — моментально записывает события в стандартный вывод (или в файл лога, если он запущен в режиме демона).

В число плагинов с буферизацией входят:

  • out_exec_filter — запускает внешнюю программу и считывает событие из её вывода;
  • out_forward — передаёт события на другие узлы fluentd;
  • out_mongo (или out_mongo_replset) — передаёт записи в БД MongoDB.

Плагины буферизации

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

  • buf_memory — изменяет объём памяти, используемой для хранения буферизованных данных (подробнее см. в официальной документации);
  • buf_file — даёт возможность хранить содержимое буфера в файле на жёстком диске.

Более подробно о том, как работают плагины буферизации, можно прочитать здесь.

Плагины форматирования

С помощью плагинов форматирования можно изменять формат данных, полученных из логов. К стандартным плагинам этой группы относятся:

  • out_file — позволяет кастомизировать данные, представленные в виде «время — тэг — запись в формате json»;
  • json — убирает из записи в формате json поле «время» или «тэг»;
  • ltsv — преобразует запись в формат LTSV;
  • single_value — выводит значение одного поля вместо целой записи;
  • csv — выводит запись в формате CSV/TSV.

Более подробно о плагинах форматирования можно прочитать здесь.

Плагины парсинга

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

Естественно, что все плагины fluentd в рамках обзорной статьи описать невозможно — это тема для отдельной публикации. С полным списком всех существующих на сегодняшний день плагинов можно ознакомиться на этой странице.

Общие параметры для всех плагинов

Для всех плагинов указываются также следующие параметры:

  • type — тип;
  • id — идентификационный номер;
  • log_level — уровень логгирования (см. выше).

На официальном сайте fluentd выложены готовые конфигурационные файлы, адаптированные под различные сценарии использования (см. здесь).

Вывод данных и интеграция с другими решениями

Собранные с помощью Fluentd могут быть переданы для хранения и дальнейшей обработки в базы данных (MySQL, PostgreSQL, CouchBase, CouchDB, MongoDB, OpenTSDB, InfluxDB) распределенные файловые системы (HDFS — см. также статью об интеграции Fluentd c Hadoop) облачные сервисы (AWS, Google BigQuery), поисковые инструменты (Elasticsearch, Splunk, Loggly).
Для обеспечения возможности поиска и визуализации данных довольно часто используется комбинация Fluentd+Elasticsearc+Kibana (подробную инструкцию по установке и настройке см., например, здесь).

Полный список сервисов и инструментов, которым Fluentd может передавать данные, размещён здесь. На официальном сайте опубликованы также инструкции по использованию Fluentd в связке с другими решениями.

Заключение

В этой статье мы представили обзор возможностей сборщика логов Fluentd, которым мы пользуемся для решения собственных задач. Если вы заинтересовались и у вас возникло желание попробовать Fluentd на практике — мы подготовили роль Ansible, которая поможет упростить процесс установки и развёртывания.

С проблемой сбора и анализа логов, наверное, сталкивались многие из вас. Было бы интересно узнать, какими инструментами вы пользуетесь для её решения и почему вы выбрали именно их. А если вы используете Fluentd — поделитесь опытом в комментариях.

Что еще почитать по теме

T-Rex 30 марта 2021

Что такое SMTP-протокол и как он устроен?

SMTP (Simple Mail Transfer Protocol) — протокол передачи почты. Он был представлен еще в 1982 году, но не теряет актуальности до сих пор. В статье разбираемся, какие задачи решает протокол и как он ра…
T-Rex 30 марта 2021
Владимир Туров 1 сентября 2020

Дело совершенно секретного iPod

Это был обычный серый день в конце 2005 года. Я сидел на рабочем месте и писал код для следующей версии iPod. Вдруг без стука ворвался директор ПО для iPod, начальник моего начальника, и закрыл дверь.
Владимир Туров 1 сентября 2020
T-Rex 21 августа 2020

TrendForce: цены на SSD упадут

Эксперты DRAMeXchange предсказывают значительное падение цен на оперативную память и твердотельные накопители в ближайшее время. Причина — сокращение спроса на чипы для NAND и DRAM.
T-Rex 21 августа 2020

Новое в блоге

Михаил Фомин 24 июня 2022

Docker Swarm VS Kubernetes — как бизнес выбирает оркестраторы

Рассказываем, для каких задач бизнесу больше подойдет Docker Swarm, а когда следует выбрать Kubernetes.
Михаил Фомин 24 июня 2022
Ульяна Малышева 30 сентября 2022

«Нулевой» локальный диск. Как мы запустили облако только с сетевыми дисками и приручили Ceph

Чем хороши сетевые диски и почему именно Ceph, рассказал директор по развитию ядра облачной платформы Иван Романько.
Ульяна Малышева 30 сентября 2022
Валентин Тимофеев 30 сентября 2022

Как проходит онбординг сотрудников ИТО? Что нужно, чтобы выйти на смену в дата-центр

Рассказываем, как обучаем новых сотрудников, какие задачи и испытания проходят инженеры прежде, чем выйти на свою первую смену.
Валентин Тимофеев 30 сентября 2022
T-Rex 28 сентября 2022

Книги по SQL: что почитать новичкам и специалистам

Собрали 6 книг, которые помогут на старте изучения SQL и при углублении в тему.
T-Rex 28 сентября 2022