Как правильно конфигурировать логгер и внедрять зависимость?

Всем привет!
У меня в проекте много классов, которые выполняют определенные задачи.
Возникла необходимость логировать.
Какие-то классы должны писать логи в файл, другие - отправлять по определенному протоколу, или одновременно в несколько источников.

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

Проблема возникла архитектурная:

т.к. перед использованием класса логгера, его нужно конфигурировать (устанавливать уровень ошибок для логирования, файл или иное хранилище для логов, формат логов и т.д.),
и это все занимает примерно 20-50 строк кода.

Варианты, которые я хотел реализовать:

1. Изначально, я думал в каждый класс добавить метод - *createLogger*, где бы конфигурировал логгер и возвращал объект. В реализации это очень просто, но это нарушение принципа SRP.
Т.к. каждый раз нужно будет лезть в класс и изменять метод, если нужно изменить формат лога, или добавить новое хранилище для лога.

2. Создать фабрику, которая будет создавать эти логгеры.
Но в этом случае, фабрика должна иметь кучу настроек, чтобы можно было сконфигурировать разные логгеры.
Этот вариант тоже отпадает, т.к. в результате будет очередной класс, который также нужно конфигурировать из десятка строк кода.

3. Внедрять зависимость логгера, через конструктор, а перед использованием класса конфигурировать логгер, и передавать через конструктор.
Вроде вариант норм. Но почти все классы проекта должны иметь логирование. Неужели у всех классов по умолчанию конструктор должен быть завален аргументами для зависимости-логгера ?

4. Какие есть варианты ? Как это правильно реализовать с точки зрения архитектуры ?
  • Вопрос задан
  • 890 просмотров
Решения вопроса 1
dmitriylanets
@dmitriylanets
веб-разработчик
5. внедрять логер в зависимости от интерфейса. В DI есть возможность вызвать метод setLogger в зависимости от интерфейса.
Например вы создаете интерфейсы:
FileLoggerAware extends LoggerAwareInterface 
MysqlLoggerAware extends LoggerAwareInterface


теперь конфигурирует DI
$container->share(FileLogger::class,function(){
       return new NullLogger;//тут реализация file логера
});
$container->share(MysqlLogger::class,function(){
      return new NullLogger;//тут реализация Mysql логера
});
$container
    ->inflector(FileLoggerAware::class)
    ->invokeMethod('setLogger', [FileLogger::class]) 
;
$container
    ->inflector(MysqlLoggerAware::class)
    ->invokeMethod('setLogger', [MysqlLogger::class]) 
;


и все в нужном классе делаешь, (но все классы должны работать через awaring di, прилетать автоматом через конструктор)
class MyClass implements FileLoggerAware
{

use LoggerAwareTrait;

}


ссылки:
https://github.com/php-fig/log/blob/master/Psr/Log...
https://container.thephpleague.com/3.x/inflectors/
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы