«Чем больше вы регистрируете, тем сложнее гадать»
Моя первая встреча с ведением журнала
Я вообще не пользовался логированием в приложениях и модулях, как многие начинающие программисты. Мой рабочий процесс для отладки и мониторинга включал использование консольных операторов и запись вывода в файлы для мониторинга в крайних случаях.
Я впервые столкнулся с производственным кодом качества, когда проходил стажировку в Amazon. Я понял, что поддерживать продукт с несколькими компонентами, состоящими из тысяч строк кода, сложно без надлежащего протоколирования событий и переходов между состояниями каждого модуля.
Одна из моих задач во время стажировки заключалась в портировании Java-компонента, который использует внешние библиотеки и зависимости для использования из SQS. Многие зависимости, которые использовались в моем модуле, имели slf4j, log4j и log4j2.x в качестве фреймворка / фасада журналирования. В этой серии статей рассматриваются трудности и проблемы, с которыми я, будучи новичком в Java, столкнулся при настройке надлежащего ведения журнала.

«Идеальный» Java-логгер
Как и многие другие концепции в информатике, мы начнем с создания модели идеального регистратора Java, добавив функциональные возможности и требования, и сравним ее с реализацией в реальном мире.
- Регистрация текста, объектов и массивов - идеальный регистратор должен уметь регистрировать текст, а также сложные объекты и их состояние.
- Множественные места назначения и подключение. Система предприятия может иметь централизованную систему ведения журналов в сети, а также локальные файлы журналов. Платформа должна иметь возможность отправлять журналы в разные целевые потоки через несколько подключений.
- Уровни журнала - программист должен иметь возможность явно указывать такие уровни журнала, как ОТЛАДКА, ИНФОРМАЦИЯ, ПРЕДУПРЕЖДЕНИЕ, FATAL и т. д. Различные уровни могут использоваться для назначения приоритета сообщению журнала и для запуска автоматизации работы. Платформа должна быть настраиваемой, чтобы записывать разные сообщения в разные места назначения в зависимости от уровня журнала.
- Конфигурации времени выполнения. Программист должен иметь возможность изменять конфигурации регистратора, такие как места назначения и уровень представления журнала во время выполнения, без необходимости повторного развертывания.
- Копирование файла журнала - во многих случаях программное обеспечение работает в течение многих лет. Если регистратор годами добавляет журналы в один и тот же файл, мы получим файлы в гигабайтовом масштабе, которые нелегко найти с помощью grep. Следовательно, регистратор должен иметь возможность динамически изменять файлы в зависимости от времени (или какого-либо другого параметра).
- Минимальное снижение производительности. Поскольку ведение журнала является второстепенным действием, оно должно выполняться с минимальным снижением производительности. Последнее, что нам нужно, - это объекты регистратора, запускающие сборщик мусора.
- Асинхронное ведение журнала. Регистратор должен иметь возможность выполнять операции ввода-вывода в другом потоке, что снижает потери производительности.
- Форматирование журнала. Бывают случаи, когда нам нужно отформатировать журнал по-разному в зависимости от выходного потока / уровня журнала. Журнал, отправляемый в системный журнал, может быть отформатирован иначе, чем тот же журнал, отправляемый на центральный сервер. Журналы FATAL могут включать идентификатор сообщения, вызвавшего сбой, тогда как журналы INFO могут не учитывать идентификатор сообщения.
- Надлежащий API и поддержка сообщества. Фреймворк должен иметь простой в использовании API, документацию и поддержку сообщества.
В следующей части мы разработаем общую архитектуру, основанную на наших требованиях к идеальному регистратору, и сравним ее с архитектурами log4j, logback и slf4j.