Symfony логирование

Установил версию 5.0.7 и разобрался как работает логирование, решил поделиться в виде конфига с комментариями.

monolog:
    # список хедлеров, которые применяются согласно порядку в котором они описаны
    handlers:
        main:
            # type: fingers_crossed - один из преднастроенных symfony-хендлеров, см:
            # vendor/symfony/monolog-bundle/DependencyInjection/MonologExtension.php:376
            # все возможные типы и их атрибуты: 
            # vendor/symfony/monolog-bundle/DependencyInjection/Configuration.php:25
            # Работает так: все log-records копятся и сохраняются только тогда, когда появляется 
            # log-record с уровнем равным или больше чем указано в action_level (см. ниже)
            type: fingers_crossed
            action_level: notice
            # получается, что в хендлере есть хедлер, значит log-record будет передана в nested
            handler: nested
            # просим symfony не логировать эксепшены, которые возникают в результате выброса 
            # которых клиенту отдается один из перечисленных здесь http-status-ов. Подробнее
            # https://symfony.com/doc/current/logging/monolog_exclude_http_codes.html и если 
            # присмотреться к сноске внизу, то видно, что это работает не всегда, например когда 
            # Symfony-эксепшен выбрасывается из какого-либо сервиса, то Symfony воспринимает это как 
            # ошибку и пытается залогировать ее.
            excluded_http_codes: [404, 405]
            formatter: App\Infrastructure\Logger\JsonFormatterDecorator
            # лучше задавать значение 1, причины:
            # - если возникает ошибка, которую не способен обработать symfony хендлер ошибок (например 
            # рекурсия или php-скрипт съел всю память и упал), то ни одна лог-запись возникшая до этого 
            # не будет записана (ведь все упадет)
            # - полезно когда логируем в нужных местах чтобы отдебажить какой-то сценарий (ряд 
            # логических действий), который конечно не завершается ошибкой, то ни одна лог-запись 
            # возникшая до этого не будет записана
            buffer_size: 1 # How many messages should be saved? Prevent memory leaks
        # т.к. данный хедлер используется в main, то это всего лишь часть хедлера main
        nested:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            level: notice
            # в dev-режиме был исключен канал событий, в проде он логируется:
            # channels: ["!event"]
        # console хендлер по-умолчанию ничего не делает, потому что его $this->output равен null, но 
        # хендлер подписан на события, которые делают 
        # setOutput( \Symfony\Component\Console\Output\StreamOutput ), подробнее:
        # \Symfony\Bridge\Monolog\Handler\ConsoleHandler::getSubscribedEvents
        console:
            type: console
            process_psr_3_messages: false
            channels: ["!event", "!doctrine"]

 

Гибкий хендлер fingers_crossed

monolog:
    handlers:
        main:
            type: fingers_crossed
            handler: nested
            # указываем удовлетворяющую стратегию фильтрации:
            activation_strategy: monolog.strategy.activation.seo_strategy
            # но, теперь настройка excluded_http_codes не работает, ведь она часть стратегии активации
        nested:
            type: stream
            path: php://stderr
            level: "debug"
            formatter: monolog.formatter.json

И теперь в файле config/services.yaml настраиваем каналы более гибко:

    # Объявляем сервис обработки логов по каналам, другими словами - фильтрация ошибок по уровню.
    # Ниже разрешаем логировать все сообщения всех каналов с уровнем NOTICE и выше, а для канала "app" 
    # все уровни начиная с DEBUG.
    Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy:
        arguments:
            $defaultActionLevel: !php/const Monolog\Logger::NOTICE
            $channelToActionLevel:
                app: !php/const Monolog\Logger::DEBUG

    # Переопределяем стратегию логирования для монолог-хендлера fingers_crossed при этом указывая
    # подавление HTTP-ошибок: 404, 405 (уровень error) так же как это делал excluded_http_codes
    monolog.strategy.activation.seo_strategy:
        class: Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy
        arguments:
            $inner: '@Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy'
            $exclusions:
                - { code: 404, urls: [] }
                - { code: 405, urls: [] }

Собственный вариант логирования

monolog:
    handlers:
        main:
            type: service
            id: My\LogHandler

Увы, указывать атрибут handler бесполезно где-либо, кроме хендлера type: fingers_crossed т.к. атрибут будет проигнорирован, например в следующем примере в оба хендлера будет передана log-record:

monolog:
    handlers:
        main:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            handler: custom
        custom:
            type: service
            id: My\LogHandler

Не документировано

В любом хендлере (кроме своего) Вы можете использовать интересный атрибут "include_stacktraces: true" благодаря которому, в log-record будут добавлены стек-трейсы всех эксепшенов, которые Вы передадите в контекст log-record, давайте на примере:

$exception1 = new \Exception();
$exception2 = new \Exception();
$logger->error('message with two exception trace', [$exception1, $exception2]);

Особенность: "include_stacktraces" работает только, если Вы используете один из следующих форматеров: JsonFormatter, LineFormatter, которые в свою очередь для преобразования эксепшена используют функцию NormalizerFormatter::normalizeException()

Каналы

Посмотреть список каналов можно командой: bin/console debug:autowiring | grep monolog

Мне выдало:

Psr\Log\LoggerInterface (monolog.logger)
Psr\Log\LoggerInterface $cacheLogger (monolog.logger.cache)
Psr\Log\LoggerInterface $consoleLogger (monolog.logger.console)
Psr\Log\LoggerInterface $deprecationLogger (monolog.logger.deprecation)
Psr\Log\LoggerInterface $doctrineLogger (monolog.logger.doctrine)
Psr\Log\LoggerInterface $eventLogger (monolog.logger.event)
Psr\Log\LoggerInterface $httpClientLogger (monolog.logger.http_client)
Psr\Log\LoggerInterface $phpLogger (monolog.logger.php)
Psr\Log\LoggerInterface $profilerLogger (monolog.logger.profiler)
Psr\Log\LoggerInterface $requestLogger (monolog.logger.request)
Psr\Log\LoggerInterface $routerLogger (monolog.logger.router)
Psr\Log\LoggerInterface $securityLogger (monolog.logger.security)
Psr\Log\LoggerInterface $translationLogger (monolog.logger.translation)

Удачи господа.

Источники: 1 - 2 - 3 - 4 - 5 - 6


01.01.2020 14:55