Logging Without a Static Logger

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

Как вы организуете ведение журнала в ваших приложениях? Я имею в виду веб-приложения, приложения командной строки или даже мобильные приложения. Думаю, у вас есть какая-то глобальная переменная или синглтон, известный как Logger, который имеет несколько методов, таких как info(), error() и debug(). Вы настраиваете его при запуске приложения, или он настраивается самостоятельно через что-то вроде log4j.properties и записывает все в консоль, файл или даже базу данных. Я делал именно так, или что-то очень похожее, много лет, пока наконец не осознал, насколько неправильный был такой подход. В одном из моих недавних Ruby-приложений я сделал все иначе, и с тех пор я намного счастливее, чем был раньше.

Хорошо, если ваше приложение простое и почти не имеет модульных или интеграционных тестов, вы будете в порядке с использованием статического журнала, который, по сути, является глобальной переменной. Однако, как мы уже обсуждали ранее, глобальные переменные - это зло. Что может пойти не так, если мы используем статический журнал? Или, другими словами, как один из моих друзей раньше говорил, в чем именно заключается проблема, которую мы собираемся решить? В основном, есть две проблемы:

  • Во-вторых, когда вы решите показать выбранную часть журнала вашему конечному пользователю, вам придется написать много кода, чтобы разделить то, что принадлежит пользователю, и то, что не принадлежит, особенно в многопоточной среде. Вам повезло, если вы используете Java и у вас есть группы потоков, но в Ruby, например, такого нет, и вам придется найти обходное решение.

Чтобы преодолеть оба этих препятствия в Zold, приложении командной строки на Ruby, я решил передавать log в качестве переменной всем классам, которым нужно вести журналирование. В Ruby это проще, чем в Java, потому что они имеют необязательные параметры. Посмотрите, например, на этот класс (конечно, это упрощенная версия):

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

Как видите, значение по умолчанию для log равно Log::NULL, которое я должен был определить самостоятельно, как значение по умолчанию для регистратора, который ничего не регистрирует. По умолчанию этот класс ничего не регистрирует. Он тихо проверяет все балансы всех кошельков и ничего не выводит. Хорошо, он что-то выводит, но никто этого не увидит.

В модульном тесте я создаю объект с несколькими методами, такими как debug(), info(), и т.д., и передаю его экземпляру класса Zold::List, который я тестирую. Другими словами, это фальшивая/поддельная версия регистратора, которую я использую для захвата всех данных, отправляемых Zold::List. Затем я могу проверить, что там есть.

Я говорю очевидные вещи? Если да, то почему у нас до сих пор есть статические регистраторы везде в Java, Ruby, PHP, C#, и т.д.? В любом случае, я рекомендую использовать внедряемую зависимость регистрации.

И да, кстати, я уверен, вы заметили изменение в названии. Это уже не logger, это log. Я уверен, вы знаете почему.

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-12-05 at 22:17

sixnines availability badge   GitHub stars