Пакет · logger

Monolog опционален

Winter Logger — тонкий слой поверх Monolog, — и всё же Monolog лишь рекомендуемая зависимость. Без него каждый логгер становится no-op. Это проектное решение, а не недосмотр, и оно формирует поведение библиотеки.

Гейт

LoggerManager::build() проверяет наличие Monolog прежде всего остального. Если класс не загружается, он возвращает PSR-3-совместимый NullLogger и останавливается:

php
private function build(string $channel): LoggerInterface
{
  if (!class_exists(MonologLogger::class)) {
      return new NullLogger();
  }
  // ... иначе строим настоящий канал Monolog
}

Поскольку channel() кэширует по имени, проверка выполняется один раз на канал. Каждый вызов логирования дальше попадает в NullLogger, чьи методы пусты — стоимость логирования при отсутствии Monolog фактически нулевая, и ничто не бросает исключений.

Почему suggest, а не require

Monolog объявлен в composer.json в секции suggest, поэтому один лишь composer require flytachi/winter-logger никогда его не подтянет. Это даёт потребителям реальный выбор:

  • Библиотеки, поддерживающие логирование опционально, могут зависеть от Winter Logger, не навязывая Monolog каждому нижестоящему приложению.
  • Микросервисы могут включать/выключать логирование по окружению, включая или исключая один пакет — без флага в конфиге, без мёртвого кода.
  • Тесты могут убрать Monolog, чтобы полностью заглушить вывод.
text
monolog/monolog установлен   →  настоящие каналы  →  форматированный вывод
monolog/monolog отсутствует  →  NullLogger        →  молчаливый no-op, без ошибки

Компромисс: молча, а не громко

Цена принципа «логирование выключается тем, что пакет не установлен» в том, что забытая установка выглядит идентично намеренной — логи просто не появляются, без предупреждения. Это принятый компромисс: библиотека трактует «нет Monolog» как валидное, поддерживаемое состояние, а не как ошибку, о которой надо кричать.

Если ваши логи пропали

Ни вывода, ни ошибки — обычно значит, что Monolog не установлен. Запустите composer require monolog/monolog, и тот же код начнёт выдавать строки — без иных правок.

Как это вписывается в философию

Это зеркалит центральное правило библиотеки: она не делает предположений о своём окружении. Она не предполагает, что Monolog присутствует, — как не читает env-переменные и не определяет рантайм. Оба решения выталкивают ответственность наружу — к приложению и фреймворку, которые знают своё окружение, — и держат сам логгер маленьким, переносимым и тривиально тестируемым.

LoggerFactory уважает тот же гейт: когда нижележащий канал — не настоящий Logger (то есть NullLogger или своя PSR-3-реализация), getLogger() возвращает его как есть, не оборачивая — так что поклассовое именование тоже вырождается корректно.

Смотрите также