company_banner

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

    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 — поделитесь опытом в комментариях.
    Если вы по тем или иным причинам не может оставлять комментарии здесь — добро пожаловать в наш блог.
    • +19
    • 42,2k
    • 8
    Selectel
    116,15
    ИТ-инфраструктура для бизнеса
    Поделиться публикацией

    Комментарии 8

      +4
      Ох намучился я с этим fluentd. При передаче JSON логов по сети иногда возникали exception'ы. Пробовал отсылать одну и ту же строку лога, exception появлялся рандомно. Отдебажить так и не получилось, слишком много времени потратил лишь на debug. Logstash хоть и монструозный, но подобными проблемами не страдает. К тому же имеет нативный output в hdfs. Во fluentd же используется WebHDFS.

      Еще существует проблема отказа коллектора логов, при условии, что логи требуется каждый час скидывать в s3. Если master упал в 10:55, то slave должен иметь все логи от 10:00 до 10:55 и отправить их ровно в 11:00 на s3.
        0
        Всем хорош Scribe, простой и надежный. Для передачи логов на центральный сервер — самое то, там их уже можно обрабатывать специализированными инструментами. Жаль Facebook перестал его поддерживать и развивать.
        Бывают конечно случаи, когда логов столько, что без распределенного хранилища (типа HDFS) не обойтись, но это будет скорее система аналитики, чем просто логгирования
          0
          Scribe правильно собрать в пакет тоже не легкая задача. По крайней мере с новыми версиями библиотек сталкиваешься с dependency hell.
          0
          Для администрирования лучше все решать стандартными средствами — типа rsyslog или syslog-ng. Первый так вообще чудо.

          Но да, все зависит от конкретных потребностей.
            0
            Андрей, спасибо за статью, но вот мне не совсем ясен принцип работы: Fluentd — это демон, запущенный где-то на ценральном сервере. Если с логами приложений более менее все ясно, используя некоторые клиентские библиотеки, я шлю соответствующее событие, то с системными логами непонятки: например, как мне собрать логи с 10 удаленных серверов? Мне нужен лог nginx access.log & error.log

            Т.е. на каждом из серверов необходимо запустить какой-то агент сборщик, или логи забираются по ssh? Не хотелось бы устанавливать агента на сервера.
              0
              Задача решается либо установкой fluent в качестве клиента, либо отправкой логов по tcp/udp средствами самого приложения. Например, nginx может слать логи в syslog over udp. Вам, конечно, целостность логов это не гарантирует, но и клиентов для сборки логов не надо будет ставить. Fluentd слушает на другом серваке по опубликованному порту. Профит. (ещё больший профит от использования logstash вместо fluentd)
                0
                Почему профит бОльший от использования logstash вместо fluentd?
                Все так пишут, но никаких аргументов не выдвигают. Какой-то холивар вечный.
                  0

                  У меня одного единственного из компании симпатию вызывает logstash вместо fluentd. Все остальные за fluentd, потому что в докере логдрайвер из коробки есть, кубернетес и вот это вот всё. А ещё регэксп, который надо всем уметь и знать по дефолту, вместо изучения онигурамы, которая хз где ещё пригодится девопсу.


                  Как по мне — если у тебя эластик стэк стоит, то какого черта делать выбор в пользу сторонних решений? Всё легче поддерживать в актуальном состоянии, у каждого компонента в стеке есть pressure control и xpack monitoring.


                  fluentd неплох, ничего не скажу, но logstash сильно изменился с тех времён когда был тяжеловесен, работал на java и ставился на каждый хост, тогда и filebeat не было. Сейчас всё иначе, но никто не хочет разбираться. Я наоборот по большей части сталкиваюсь с предпочтениями fluentd логсташу.

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

            Самое читаемое