Logging brick

Помилку треба не лише показати користувачу, а й залишити слід для діагностики. PHP error_log вистачає на ранньому кроці ErrorHandling, але для рівнів, ротації й каналів потрібен Monolog. addLogging() на ConceptStack реєструє extension-logger-monolog як LoggerInterface. Повертає LoggingBuilder. Рецепт — Логування.

Handlers додаються явно (toRotatingFile, toStderr, withHandler): без sink logger не має куди писати — свідомий fail-fast замість «тихого» no-op. ErrorHandling з setLogReporting(logger: true) вимагає цієї capability. Окремі sinks валідації / SQL (withLogging на Validation / Database) — це не цей brick.

Методи LoggingBuilder:

Метод Параметри Опис Залежність
setLevel() string $level Default Monolog level для наступних helper-ів (DEBUG, INFO, ERROR, …) —
setChannel() string $channel Ім’я каналу Monolog (з’являється в рядку логу) —
toRotatingFile() string $path, int $maxFiles = 7, ?string $level = null RotatingFileHandler —
toStderr() ?string $level = null StreamHandler на php://stderr —
withHandler() HandlerInterface $handler Будь-який готовий Monolog handler —
withMasking() — Маскування чутливих полів у логах addMasking()

setLevel()

$stack->addLogging()
    ->setLevel('DEBUG');

Базовий поріг для наступних toRotatingFile() / toStderr(), якщо їм не передати власний $level. На проді часто ERROR / WARNING, локально — DEBUG. Невідома назва → Monolog Debug.

setChannel()

$stack->addLogging()
    ->setChannel('recipes');

Ім’я в рядку логу (наприклад recipes.INFO: …) — щоб у спільному файлі / агрегаторі відрізняти додатки або середовища без окремих шляхів.

toRotatingFile()

$stack->addLogging()
    ->setLevel('ERROR')
    ->setChannel('recipes')
    ->toRotatingFile($rootPath . 'storage/logs/app.log', 7);

Типовий sink для довгоживучого додатку: файл + ротація, щоб диск не заповнювався. Абсолютний шлях, кількість ротацій; опційний третій аргумент — рівень лише для цього handler. Можна викликати кілька разів (кілька handlers: наприклад ERROR у файл і WARNING у stderr).

toStderr()

$stack->addLogging()
    ->toStderr('WARNING');

Коли логи збирає Docker / Kubernetes з stdout/stderr, а не volume з файлами — пишіть у php://stderr. Зручно для CLI і контейнерів без окремого log-директору.

withHandler()

$stack->addLogging()
    ->withHandler(new StreamHandler('php://stdout', Level::Info));

Escape hatch: Syslog, Slack, Elasticsearch тощо — будь-який готовий Monolog\Handler\HandlerInterface, коли toRotatingFile / toStderr недостатньо. Glue збирає handler сам і передає в Stack; можна викликати кілька разів поряд із іншими sinks.

withMasking()

$stack->addMasking()
    ->setPatterns([ /* regex у рядках message/trace */ ])
    ->setKeyPatterns([ /* /^email$/i, /.*password.*/i, … */ ]);

$stack->addLogging()
    ->toRotatingFile($rootPath . 'storage/logs/app.log')
    ->withMasking();

Без цього виклику addMasking() лише реєструє правила — app-логер їх не застосовує. Opt-in навмисний: той самий masker пізніше можна повісити на query log, не чіпаючи інші sinks. Key patterns ховають значення структурованого context; string patterns — фрагменти вже «розчинені» в тексті. Навіщо обидва й типовий рецепт — Логування і маскування; API правил — Masking brick.

Що реєструє brick

  • LoggerInterface (PSR-3 + Concept) — інжект у controllers/services
  • Handlers з builder — у Monolog logger

Після цього в ErrorHandling можна переключити setLogReporting(logger: true, …) — report піде в той самий канал, що й ручні $logger->info().

Рецепт — 8. Логування і маскування. Поруч — ErrorHandling brick (спочатку показуємо помилку, потім підключаємо Monolog + masking).