Есть в Джаве одна вещь, которая сделана очень, очень плохо — минус бесконечность по любой шкале. Это логирование, причем как встроенное, так и сторонее. Справедливости ради, оно плохо сделано везде, но это слабое оправдание.

Первая причина — сугубо внутренняя. Джависты — это люди, которые могут раздуть код в десять строчек на десять пакетов. Любое хорошее начинание превращается в Лунапарк с официальным сайтом, платной версией и уродской документацией.

Хорошим примером служит история с Log4j. Когда я читал, что было под капотом, вставали волосы во всех местах. Ощущение, что разработчики объехали все сумасшедшие дома, записали пожелания пациентов и выполнили их дословно. Добавьте в шаблоны Тьюринг-полный язык? Хорошая идея. Хочу подгрузку классов по урлам? Считайте, уже сделано. Напишите фасад над фасадом над фасадом? Уже в этом релизе.

Итог понятен: если громоздить подобные вещи, окажутся уязвимости. В результате целый месяц люди чинили интернет, корпоративный софт, Майнкрафт(!) и все остальное.

Вторая причина объясняется одним словом — состояние. В Джаве и других языках логирование устроено одинаково. В памяти сидит глобальный маршрутизатор, который определяет, куда какие логи складывать. У этого подхода много бед. Первая — инициация происходит неявно, например при чтении файла logback.xml из ресурсов. Вторая — программная настройка довольно сложна: нужно два экрана кода, чтобы связать фабрики логгеров с фабриками аппендеров.

Третья, которая заслуживает отдельного абзаца — это то, что я называю “воровство работы”. Как быть, если библиотека А использует log4shit, а В — log4crap? В этом случае log4crap переопределяет настройки log4shit, направляя поток сообщений в свой маршрутизатор. Повторюсь, все это происходит неявно, потому что покрыто “легковесными” фасадами.

Долгое время я думал, что logback (вроде бы самая адекватная библиотека логирования) — самостоятельное решение. Оказалось, это всего лишь фасад над уродским slf4j. Представьте себе объем работы и глубину стека вызовов! Один вагон классов для базовой функциональности, второй — чтобы приделать ему человеческое лицо.

Разобраться, почему этот лог идет сюда, а не туда, бывает очень трудно. Логирование настраивают в муках, а потом боятся на него дышать.

Глобальное логирование простительно языкам эпохи Си. В последнем есть подсистема syslog (системный журнал), которую однажды открыл и пишешь из любого места программы. По современным меркам такой подход устарел.

На мой взгляд, проблема решается тем, чтобы убрать из логирования состояние. Система предлагает интерфейс Logger с методами debug, info, error и другими. Есть реализации этого интерфейса для записи в консоль, файл, системный журнал. Конкретная реализация нас не волнует: мы просто передаем объект logger, трактуя его как экземпляр интерфейса.

Этот логгер можно (и нужно) передавать в конструктор класса. Например, в каждое подключение к базе можно передать свой логгер. То же самое относится к парсерам, серверам и так далее.

Это решает проблемы, упомянутые выше. Базовые логгеры для консоли и файла у нас есть. Можно сделать классы-комбо, которые принимают несколько логгеров и пишут сообщения в каждый. Можно сделать асинхронный логгер, можно прикрутить Кафку, CloudWatch, словом — что угодно. Достаточно унаследовать класс от интерфейса Logger и инициировать ресурсы в конструкторе.

Попутно решается проблема тестов: я могу передать логгер, который складирует сообщения в память и потом их прочитать.

Смысл в том, что убрав состояние, ты кардинально снижаешь сложность программы, а значит — стоимость ее сопровождения, в том числе ментальную.

Увы, сегодня мы бесконечно далеки от такого подхода. Во-первых, Джависты поднимут лай, во-вторых, уже написаны десятки тысяч библиотек на базе log4shit, log4crap и прочих поделок. Мы обречены поддерживать этот цирк.

Поэтому меня лихорадит, когда в Кложурной слаке кидают анонс: гайз, я написал библиотеку логирования, это легковесный фасад поверх очередного log4shit. Иные отчаянные ребята пишут логирование с нуля, но идут по тем же граблям: оно глобально, не гибко, не очевидно, и хочется захлопнуть ноутбук.

Заметка самому себе — попытаться написать нормальный логгер. Верю, что это возможно.