Логи приложений редко бывают вежливыми. Одна ошибка в java-приложении разворачивается в десяток строк стектрейса, а системы сбора по умолчанию читают файл построчно, и каждая строка превращается в отдельное событие. Вместо одного понятного инцидента поиск по хранилищу возвращает разрозненные обрывки: строка с исключением здесь, строки с именами методов там. Filebeat решает задачу на входе: сборщик читает файлы, склеивает многострочные записи по правилам и доставляет события в Elasticsearch уже в человеческом виде. Статья разбирает модель работы сборщика, настройку входов, механику реестра смещений, правила склейки для java-стектрейсов, поведение при ротации логов и порядок внедрения.
Место Filebeat в конвейере логов и модель работы сборщиков
Задача доставки логов делится на две роли: собрать с машины и разобрать в структуру. Тяжёлые разборщики умеют всё, но стоят дорого на каждом сервере, и индустрия давно пришла к разделению: на машинах работают лёгкие сборщики, а разбор и обогащение происходят ближе к хранилищу. Filebeat занимает нишу именно лёгкого сборщика: он читает файлы, минимально их готовит и отправляет, не занимаясь сложными преобразованиями.
Модель работы проста и от этого надёжна. На каждый файл назначается отдельный читатель, который ведёт его от текущей позиции до конца и просыпается на новые строки. Собранные строки складываются в очередь отправки, а дальше работает модуль доставки с повторными попытками и подтверждениями. Ничего лишнего, и именно эта простота делает сборщик пригодным для установки на десятки машин без заметного следа на ресурсах.
Лёгкость не означает примитивность. Сборщик умеет добавлять собственные поля к событиям, фильтровать строки на входе, склеивать многострочные записи и работать с готовыми модулями под распространённые форматы. Для сложных случаев предусмотрен путь через промежуточный разборщик, куда сборщик отправляет сырьё, а тот делает тяжёлую работу. Оба сценария валидны, и выбор между ними зависит от сложности разбора, а не от моды.
Отдельное преимущество ниши, предсказуемость. Сборщик не строит индексов, не хранит историю, его конфигурация умещается в один понятный файл. Отладка сводится к чтению собственного журнала сборщика и сравнению того, что появилось в хранилище, с тем, что лежит в исходном файле. Простота диагностики со временем оказывается дороже любых фич.
Настройка входов и слежение за файлами с реестром смещений
Вход задаётся типом и списком путей. Тип чтения файлов подходит почти всем сценариям, пути перечисляются с шаблонами или без, рядом опционально добавляются поля и метки, которые поедут с каждым событием. Базовый вход выглядит скромно:
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/app/*.log
fields:
app: billing
env: production
Ключевая деталь механизма, реестр смещений. Сборщик хранит файл состояния, где для каждого отслеживаемого файла зафиксирована позиция чтения. После перезапуска службы чтение продолжается ровно с места остановки, без повторов и пропусков. Понимание этого факта меняет отношение к проблемам: если события не доехали, вопрос не к смещениям, а к сети, фильтрам или хранилищу.
Идентичность файла в реестре строится по нескольким признакам, а не по одному имени. Файл может быть переименован ротацией, и сборщик узнаёт его по внутренним меткам и продолжает читать до конца под новым именем. Поведение скучное и правильное: старая копия дочитывается, новая начинается с нуля, ничего не теряется на стыке.
Гигиена реестра входит в обслуживание. Файл состояния занимает место, растёт с числом файлов и со временем сам подчищается, но при тестовых прогонах с лишними путями он обрастает мусорными записями. Практики держат правило: тестовые конфигурации прогоняются с отдельным файлом состояния, чтобы не засорять рабочий.
Multiline для java-стектрейсов и прочих многострочных записей
Склейка строк задаётся тремя параметрами: шаблоном, инверсией и направлением присоединения. Логика читается так: если строка совпадает с шаблоном, она начинает новую запись, а все несовпадающие строки присоединяются к предыдущей записи. Для java-стектрейсов классическое решение строится на том, что первая строка ошибки начинается с даты, а продолжение начинается с пробела, табуляции или служебных слов:
multiline:
pattern: '^\s|at |Caused by'
negate: true
match: after
Инверсия означает, что шаблон описывает продолжение, а не начало: совпавшая строка прикрепляется к предыдущей, несмолевшая строка открывает новую запись. Направление после означает прикрепление вниз, к последней прочитанной строке. Такая конфигурация собирает типовой стектрейс целиком: заголовок ошибки, кадры вызовов, вложенные причины.
Вторая вечная проблема многострочности, закрытие записи. Если приложение молчит, последняя незавершённая группа ждёт продолжения, и событие застревает в сборщике. Параметр тайм-аута решает это честно: по истечении интервала группа отправляется как есть. Интервал выбирается короче типичной паузы между записями, но достаточно длинный, чтобы не рубить живые стектрейсы на куски. Рядом живёт лимит числа строк в группе, страхующий от катакомб ошибочной конфигурации, при которой весь файл склеивается в одно событие.
Отдельная дисциплина нужна под форматы без явного начала записи. Если приложение пишет свободный текст без дат, шаблон начала строится по контексту: маркеры уровня, служебные префиксы, пустая строка как разделитель. Универсального шаблона не существует, и правильный порядок работы выглядит так: открыть живой файл, отобрать десяток реальных записей, построить шаблон по ним, прогнать сборщик и сравнить результат в хранилище с исходным файлом. Пятнадцать минут такой калибровки экономят месяцы недоумений.
Взаимодействие с ротацией логов на стороне источника
Ротация на источнике это та самая сцена, где встречаются механика переименования и механика идентичности файлов. При классической ротации файл переименовывается, а приложению отправляется сигнал открыть новый. Сборщик продолжает дочитывать переименованный файл до конца и одновременно открывает новый, стык проходит без потерь.
Режим копирования с обрезанием ведёт себя иначе и заслуживает отдельного знания. Файл копируется, а оригинал обрезается на месте: внутренние метки файла меняются, и сборщик воспринимает это как новый файл. Возможны обе неприятности: часть строк, написанных между копированием и обрезанием, может не попасть в копию, а смятённая идентичность иногда рождает дубли. Риск оценивается честно: при спокойных потоках он невелик, при плотных он реален, и там, где выбор возможен, предпочтительнее ротация с переименованием и сигналом приложению.
Сжатие скрученных копий тоже затрагивает сборщик, но косвенно. Сжатые архивы не читаются, и в путях входа они либо не попадают под шаблоны, либо попадают под исключения. Практика решения: шаблоны путей покрывают только живые файлы, архивы лежат рядом с расширением сжатия и остаются вне поля зрения сборщика.
Всё это знание сводится к простому чек-листу перед внедрением на новом приложении: тип ротации выяснен, шаблоны путей не ловят архивы, стык ротации проверен тестовым прогоном. Три пункта, и поведение сборщика перестаёт быть источником сюрпризов навсегда.
Выход в Elasticsearch и базовый порядок индексов
Выход в хранилище задаётся адресами и именем индекса. Адреса перечисляются списком, имя формируется из префикса и окружения, события несут собственные поля, по которым хранилище строит свои представления. Базовая настройка умещается в несколько строк, и работоспособность проверяется встроенной командой теста соединения до первого запуска в бою.
output.elasticsearch:
hosts: ["storage.example.internal:9200"]
index: "app-%{[fields.env]}"
Порядок индексов планируется в ту же минуту, что и первое событие. Хранилище, в которое всё валится одним потоком, деградирует предсказуемо: индекс растёт, запросы замедляются, место кончается внезапно. Зрелая схема строится на индексах по дням или неделям с политикой хранения, по которой старые индексы сжимаются и исчезают по расписанию. Имена индексов согласуются с этой политикой сразу, а не переделываются потом через переиндексацию.
Для тяжёлых преобразований предусмотрен путь через промежуточный разборщик. Сборщик отправляет сырьё туда, разборщик обогащает и раскладывает по индексам. Граница проходит по сложности: шаблоны и мелкие правки живут в сборщике, грамматические разборы и обогащение живут в разборщике. Смешивание ролей работает, но расплачивается сложностью отладки, и держать границу осознанно дешевле, чем чинить её каждую аварию.
Нагрузка на хранилище контролируется на стороне сбора. Пакетная отправка, размер пакета и число параллельных отправителей настраиваются под пропускную способность, фильтры на входе отрезают заведомо ненужные строки, а шумные отладочные логи вообще не подключаются. Хранилище, в которое попадает только нужное, живёт дольше и отвечает быстрее, и эта экономия закладывается ещё в конфигурации сборщика.
Проверка и контроль доставки
Внедрение начинается с проверок конфигурации и соединения. Встроенная команда теста разбирает файл настроек и указывает на ошибки синтаксиса до запуска, команда теста выхода проверяет достижимость хранилища и права. Обе выполняются за секунды, и пропускать их можно только при полном отсутствии интереса к результату.
Собственный журнал сборщика читается теми же глазами, что и любой системный журнал: при старте служба пишет ход инициализации, при работе жалуется на недоступность выхода и на проблемы чтения файлов. Первые минуты после внедрения стоит просто следить за этим журналом в реальном времени, и девять из десяти проблем обнаруживаются именно там.
Дальше работает сверка сторон. В исходном файле пишется тестовое многострочное сообщение с уникальной меткой, в хранилище ищется событие по этой метке, проверяется, что все строки приехали одним событием. Такая сквозная проверка закрывает главный вопрос внедрения, склейку, фактом, а не предположением. За ней идут суточное наблюдение за счётчиками отправки и разбор первых настоящих ошибок, которые неизбежно появляются в любой системе.
Регулярный контроль держится на трёх привычках: мониторинг счётчиков отправки и ошибок, сверка объёмов между исходными файлами и хранилищем по крупным событиям, и периодическая проверка файла состояния на разумный размер. Ничего экзотического, но именно эти привычки превращают доставку логов из работает как-то в работает проверенно.
Рабочая процедура внедрения Filebeat на сервере приложения
Порядок внедрения, собранный из практики, выглядит так:
- Изучение формата логов приложения и выбор шаблона склейки по живым записям;
- Настройка входа с полями окружения и исключением архивов из путей;
- Настройка выхода с именем индекса и согласованной политикой хранения;
- Тест конфигурации и соединения до первого запуска;
- Сквозная проверка с уникальной меткой и многострочным тестовым сообщением;
- Суточное наблюдение за счётчиками и первый разбор настоящей ошибки.
Процедура закрывает главные места риска: формат записей, стык ротации, имя индекса и склейка. Каждый пункт проверяется минутами, а непроверенный пункт позже стоит часами, и арифметика здесь не в пользу лени.
Итоговое суждение о сборщике скромное и рабочее. Filebeat не разбирает логи, не строит красивых панелей и не решает за команду, что считать ошибкой. Он делает ровно одну работу, читает файлы, склеивает записи по правилам и доставляет события без потерь, и делает её предсказуемо. Многострочные java-стектрейсы, собранные в цельные события, это то отличие, которое видно с первого дня и которое экономит минуты на каждом инциденте. Инфраструктура наблюдения сильна ровно настолько, насколько сильна её самая ранняя ступень, и ступень этой доставки заслуживает того самого часа внимательной настройки.