Логирование в Джаве
Есть в Джаве одна вещь, которая сделана очень, очень плохо — минус бесконечность по любой шкале. Это логирование, причем как встроенное, так и сторонее. Справедливости ради, оно плохо сделано везде, но это слабое оправдание.
Первая причина — сугубо внутренняя. Джависты — это люди, которые могут раздуть код в десять строчек на десять пакетов. Любое хорошее начинание превращается в Лунапарк с официальным сайтом, платной версией и уродской документацией.
Хорошим примером служит история с Log4j. Когда я читал, что было под капотом, вставали волосы во всех местах. Ощущение, что разработчики объехали все сумасшедшие дома, записали пожелания пациентов и выполнили их дословно. Добавьте в шаблоны Тьюринг-полный язык? Хорошая идея. Хочу подгрузку классов по урлам? Считайте, уже сделано. Напишите фасад над фасадом над фасадом? Уже в этом релизе.
Итог понятен: если громоздить подобные вещи, окажутся уязвимости. В результате целый месяц люди чинили интернет, корпоративный софт, Майнкрафт(!) и все остальное.
Вторая причина объясняется одним словом — состояние. В Джаве и других языках логирование устроено одинаково. В памяти сидит глобальный маршрутизатор, который определяет, куда какие логи складывать. У этого подхода много бед. Первая — инициация происходит неявно, например при чтении файла logback.xml из ресурсов. Вторая — программная настройка довольно сложна: нужно два экрана кода, чтобы связать фабрики логгеров с фабриками аппендеров.
Третья, которая заслуживает отдельного абзаца — это то, что я называю “воровство работы”. Как быть, если библиотека А использует log4shit, а В — log4crap? В этом случае log4crap переопределяет настройки log4shit, направляя поток сообщений в свой маршрутизатор. Повторюсь, все это происходит неявно, потому что покрыто “легковесными” фасадами.
Долгое время я думал, что logback (вроде бы самая адекватная библиотека логирования) — самостоятельное решение. Оказалось, это всего лишь фасад над уродским slf4j. Представьте себе объем работы и глубину стека вызовов! Один вагон классов для базовой функциональности, второй — чтобы приделать ему человеческое лицо.
Разобраться, почему этот лог идет сюда, а не туда, бывает очень трудно. Логирование настраивают в муках, а потом боятся на него дышать.
Глобальное логирование простительно языкам эпохи Си. В последнем есть подсистема syslog (системный журнал), которую однажды открыл и пишешь из любого места программы. По современным меркам такой подход устарел.
На мой взгляд, проблема решается тем, чтобы убрать из логирования состояние. Система предлагает интерфейс Logger с методами debug, info, error и другими. Есть реализации этого интерфейса для записи в консоль, файл, системный журнал. Конкретная реализация нас не волнует: мы просто передаем объект logger, трактуя его как экземпляр интерфейса.
Этот логгер можно (и нужно) передавать в конструктор класса. Например, в каждое подключение к базе можно передать свой логгер. То же самое относится к парсерам, серверам и так далее.
Это решает проблемы, упомянутые выше. Базовые логгеры для консоли и файла у нас есть. Можно сделать классы-комбо, которые принимают несколько логгеров и пишут сообщения в каждый. Можно сделать асинхронный логгер, можно прикрутить Кафку, CloudWatch, словом — что угодно. Достаточно унаследовать класс от интерфейса Logger и инициировать ресурсы в конструкторе.
Попутно решается проблема тестов: я могу передать логгер, который складирует сообщения в память и потом их прочитать.
Смысл в том, что убрав состояние, ты кардинально снижаешь сложность программы, а значит — стоимость ее сопровождения, в том числе ментальную.
Увы, сегодня мы бесконечно далеки от такого подхода. Во-первых, Джависты поднимут лай, во-вторых, уже написаны десятки тысяч библиотек на базе log4shit, log4crap и прочих поделок. Мы обречены поддерживать этот цирк.
Поэтому меня лихорадит, когда в Кложурной слаке кидают анонс: гайз, я написал библиотеку логирования, это легковесный фасад поверх очередного log4shit. Иные отчаянные ребята пишут логирование с нуля, но идут по тем же граблям: оно глобально, не гибко, не очевидно, и хочется захлопнуть ноутбук.
Заметка самому себе — попытаться написать нормальный логгер. Верю, что это возможно.
Нашли ошибку? Выделите мышкой и нажмите Ctrl/⌘+Enter