В комментариях к моему туториалу, рассказывающему о парсинге логов с помощью Fluent-bit, было приведено две альтернативы: Filebeat и Vector. Этот туториал рассказывает как организовать сбор и парсинг лог-сообщений при помощи Filebeat.
Цель туториала: Организовать сбор и парсинг лог-сообщений с помощью Filebeat.
Дисклеймер: Туториал не содержит готовых для продакшена решений, он написан с целью помочь тем кто только начинает разбираться с filebeat и для закрепления изученного материала автором. Так же в туториале не проводиться сравнение доставщиков логов. Сравнение можно найти здесь.
Кому данная тема интересна, прошу под кат:)
Тестовое приложение будем запускать с помощью docker-compose.
Общая информация
Filebeat — это легковесный доставщик лог-сообщений. Принцип его работы состоит в мониторинге и сборе лог-сообщений из лог-файлов и пересылки их в elasticsearch или logstash для индексирования.
Filebeat состоит из ключевых компонентов:
- сборщики (harvesters) — отвечают за чтение лог-файлов и отправку лог-сообщений в заданный выходной интерфейс, на каждый лог-файл задается отдельный сборщик;
- входные интерфейсы (inputs) — отвечают за поиск источников лог-сообщений и управление сборщиками.
Подробнее о принципе работы можно почитать в официальном руководстве.
Организация сбора лог-сообщений
Filebeat имеет множество входных интерфейсов для различных источников лог-сообщений. В рамках туториала предлагаю двигаться от настройки сбора вручную до автоматического поиска источников лог-сообщений в контейнерах. По моему мнению данный подход позволит глубже понять filebeat, к тому же я сам двигался тем же путем.
Нам необходим сервис, лог-сообщения которого будем пересылать на хранение.
В качестве такого сервиса возьмем простое приложение, написанное с помощью FastAPI, единственной целью которого является генерация лог-сообщений.
Сбор лог-сообщений с помощью volume
Для начала клонируем репозиторий. В нем находится тестовое приложение, конфигурационный файл Filebeat и docker-compose.yml.
Настройка сбора лог-сообщений с помощью volume состоит из следующих шагов:
- Настройка логгера приложения на запись лог-сообщений в файл:
app/api/main.py
logger.add( "./logs/file.log", format="app-log - {level} - {message}", rotation="500 MB" )
Создание volume для хранения лог-файлов вне контейнеров:
docker-compose.yml
version: "3.8" services: app: ... volumes: # создаем volume, для хранения лог-файлов вне контейнера - app-logs:/logs log-shipper: ... volumes: # заменяем конфигурационный файл в контейнере - ./filebeat.docker.yml:/usr/share/filebeat/filebeat.yml:ro # подключаем volume с лог-файлами в контейнер - app-logs:/var/app/log volumes: app-logs:
Определение входного и выходного интерфейсов filebeat:
filebeat.docker.yml
filebeat.inputs: - type: log # Определяем путь к лог-файлам paths: - /var/app/log/*.log # Пока будем выводить лог-сообщения в консоль output.console: pretty: true
Запускаем тестовое приложение, генерируем лог-сообщения и получаем их в следующем формате:
{ "@timestamp": "2021-04-01T04:02:28.138Z", "@metadata": { "beat": "filebeat", "type": "_doc", "version": "7.12.0" }, "ecs": { "version": "1.8.0" }, "host": { "name": "aa9718a27eb9" }, "message": "app-log - ERROR - [Item not found] - 1", "log": { "offset": 377, "file": { "path": "/var/app/log/file.log" } }, "input": { "type": "log" }, "agent": { "version": "7.12.0", "hostname": "aa9718a27eb9", "ephemeral_id": "df245ed5-bd04-4eca-8b89-bd0c61169283", "id": "35333344-c3cc-44bf-a4d6-3a7315c328eb", "name": "aa9718a27eb9", "type": "filebeat" } }
Сбор лог-сообщений с помощью входного интерфейса container
Сontainer позволяет осуществлять сбор лог-сообщений с лог-файлов контейнеров.
Настройка сбора лог-сообщений с помощью входного интерфейса container состоит из следующих шагов:
- Удаление настроек входного интерфейса log, добавленного на предыдущем этапе, из конфигурационного файла.
Определение входного интерфейса container в конфигурационном файле:
filebeat.docker.yml
filebeat.inputs: - type: container # путь к лог-файлам контейнеров paths: - '/var/lib/docker/containers/*/*.log' # Пока будем выводить лог-сообщения в консоль output.console: pretty: true
- Отключаем volume app-logs из сервисов app и log-shipper и удаляем его, он нам больше не понадобиться.
Подключаем к сервису log-shipper лог-файлы контейнеров и сокет докера:
docker-compose.yml
version: "3.8" services: app: ... log-shipper: ... volumes: # заменяем конфигурационный файл в контейнере - ./filebeat.docker.yml:/usr/share/filebeat/filebeat.yml:ro - /var/lib/docker/containers:/var/lib/docker/containers:ro - /var/run/docker.sock:/var/run/docker.sock:ro
- Настройка логгера приложения на запись лог-сообщений в стандартный вывод:
app/api/main.py
logger.add( sys.stdout, format="app-log - {level} - {message}", )
Входной интерфейс container, настроенный таким образом, будет собирать лог-сообщения со всех контейнеров, однако может потребоваться собирать лог-сообщения только с определенных контейнеров.
Это можно сделать описанным ниже способом.
Сбор лог-сообщений с помощью автообнаружения
При сборе лог-сообщений контейнеров, могут возникнуть трудности, так как контейнеры могут перезапускаться, удаляться и т.д. В связи с этим в filebeat есть автообнаружение контейнеров, с возможностью определения настроек сбора лог-сообщений для каждого обнаруженного контейнера. Механизм автообнаружения состоит из двух частей:
- шаблона поиска контейнера;
- конфигурации сбора лог-сообщений.
Подробнее можно почитать здесь.
Настройка состоит из следующих шагов:
- Удаление настроек входного интерфейса container, добавленного на предыдущем этапе, из конфигурационного файла.
Определение настроек автообнаружение в конфигурационном файле:
filebeat.docker.yml
filebeat.autodiscover: providers: # искать docker контейнер - type: docker templates: - condition: contains: # имя которого fastapi_app docker.container.name: fastapi_app # определим конфигурацию сбора для этого контейнера config: - type: container paths: - /var/lib/docker/containers/${data.docker.container.id}/*.log # исключим лог-сообщения asgi-сервера exclude_lines: ["^INFO:"] # Пока будем выводить лог-сообщения в консоль output.console: pretty: true
Вот и все. Теперь filebeat будет собирать лог-сообщения только с указанного контейнера.
Сбор лог-сообщений с использованием подсказок (hints)
Filebeat поддерживает автообнаружение на основе подсказок.
Он ищет информацию (подсказки) о конфигурации сбора в лейблах контейнера.
Как только контейнер запустится, Filebeat проверит, содержит ли он какие-либо подсказки, и запустит для него сбор с правильной конфигурацией.
Подробнее можно почитать здесь.
Настройка сбора состоит из следующих шагов:
Удаляем шаблон обнаружения сервиса app и включаем подсказки:
filebeat.docker.yml
filebeat.autodiscover: providers: - type: docker hints.enabled: true # Пока будем выводить лог-сообщения в консоль output.console: pretty: true
Отключаем сбор лог-сообщения для сервиса log-shipper:
docker-compose.yml
version: "3.8" services: app: ... log-shipper: ... labels: co.elastic.logs/enabled: "false"
Парсинг лог-сообщений
Для обработки лог-сообщений в Filebeat есть большое количество обработчиков (processors).
Их можно подключить с помощью лейблов контейнеров либо определить в конфигурационном файле.
Воспользуемся вторым способом.
Для начала очистим лог-сообщения от метаданных. Для этого в конфигурационный файл добавим обработчик drop_fields:
filebeat.docker.yml
processors: - drop_fields: fields: ["agent", "container", "ecs", "log", "input", "docker", "host"] ignore_missing: true
Теперь лог-сообщение выглядит следующим образом:
{ "@timestamp": "2021-04-01T04:02:28.138Z", "@metadata": { "beat": "filebeat", "type": "_doc", "version": "7.12.0" }, "message": "app-log - ERROR - [Item not found] - 1", "stream": ["stdout"] }
Для отделения лог-сообщений API от лог-сообщений asgi-сервера, добавим к ним тег с помощью обработчика add_tags:
filebeat.docker.yml
processors: - drop_fields: ... - add_tags: when: contains: "message": "app-log" tags: [test-app] target: "environment"
Структурируем поле message лог-сообщения с помощью обработчика dissect и удалим его с помощью drop_fields:
filebeat.docker.yml
processors: - drop_fields: ... - add_tags: ... - dissect: when: contains: "message": "app-log" tokenizer: 'app-log - %{log-level} - [%{event.name}] - %{event.message}' field: "message" target_prefix: "" - drop_fields: when: contains: "message": "app-log" fields: ["message"] ignore_missing: true
Теперь лог-сообщение выглядит следующим образом:
{ "@timestamp": "2021-04-02T08:29:07.349Z", "@metadata": { "beat": "filebeat", "type": "_doc", "version": "7.12.0" }, "log-level": "ERROR", "event": { "name": "Item not found", "message": "Foo" }, "environment": [ "test-app" ], "stream": "stdout" }
Дополнение
Filebeat так же имеет готовые решения сбора и парсинга лог-сообщений для широко используемых инструментов таких, как Nginx, Postgres и т.д.
Они называются модулями.
К примеру для сбора лог-сообщений Nginx, достаточно добавить к его контейнеру лейбл:
co.elastic.logs/module: "nginx"
и включить подсказки в конфигурационном файле. После этого мы получим готовое решение для сбора и парсинга лог-сообщений + удобный dashboard в Kibana.
Всем спасибо за внимание!