Добавление имени обработчика в логи Monolog от Symfony

Я использую собственный монолог-процессор, как описано здесь, и мне нужно чтобы добавить имя обработчика в мои журналы. Фрагмент кода по приведенным выше ссылкам показывает, что аргумент передается как сеанс. Как я могу передать аргумент обработчика?

    app.logger.session_request_processor:
        class: AppBundle\Logger\SessionRequestProcessor
        arguments:  ['@session']
        tags:
            - { name: monolog.processor, method: processRecord }

person ghdna    schedule 17.04.2018    source источник


Ответы (1)


Это не так просто, как кажется. Процессор либо зарегистрирован в регистраторе или через обработчик.

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

Чтобы решить эту проблему, вы можете добавить CompilerPass, который выполняет ручную работу. для тебя.

Предположим, у нас есть этот процессор

class HandlerProcessor
{
    /**
     * @var string
     */
    private $handlerName;

    public function __construct($handlerName)
    {
        $this->handlerName = $handlerName;
    }

    public function processRecord(array $record)
    {
        $record['extra']['handler_name'] = $this->handlerName;

        return $record;
    }
}

С помощью этого процессора вы можете затем создать проход компилятора, который создает все определения для различных созданных монологов обработчиков.

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

class HandlerProcessorPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (!$container->hasParameter('monolog.handlers_to_channels')) {
            return;
        }

        foreach ($container->getParameter('monolog.handlers_to_channels') as $handlerId => $channels) {
            $definition = new Definition(HandlerProcessor::class);
            $handlerDefinition = $container->getDefinition($handlerId);

            $handlerName = $handlerDefinition->getClass();
            $definition->addArgument($handlerName);

            $handlerProcessorId = 'handler_processor.' . $handlerId;
            $container->setDefinition($handlerProcessorId, $definition);

            $handlerDefinition->addMethodCall('pushProcessor', array(new Reference($handlerProcessorId)));
        }
    }
}

Поскольку проходы компилятора могут быть довольно запутанными, если вы никогда не использовали их раньше, давайте построчно:

if (!$container->hasParameter('monolog.handlers_to_channels')) {
    return;
}

Это проверяет, зарегистрирован ли пакет monolog. Параметр monolog.handlers_to_channels добавляется в контейнер в MonologExtension< /а>. Сам параметр содержит массив, где ключ — это имя идентификатора обработчика, а значение — массив со всеми каналами, на которых зарегистрирован этот обработчик (или нуль, если этот обработчик действителен для всех каналов).

foreach ($container->getParameter('monolog.handlers_to_channels') as $handlerId => $channels) {
    $definition = new Definition(HandlerProcessor::class);
    $handlerDefinition = $container->getDefinition($handlerId);

Здесь мы создаем новое определение нашего HandlerProcessor и получаем определение текущего обрабатываемого обработчика.

$handlerName = $handlerDefinition->getClass();
$definition->addArgument($handlerName);

Это позволит получить имя класса обработчика (например, Monolog\Handler\SlackHandler) и добавляет его в качестве аргумента конструктора в HandlerProcessor

$handlerProcessorId = 'handler_processor.' . $handlerId;
$container->setDefinition($handlerProcessorId, $definition);

$handlerDefinition->addMethodCall('pushProcessor', array(new Reference($handlerProcessorId)));

И последнее, но не менее важное: мы создаем новый идентификатор для определения процессора, которое мы только что создали в начале цикла foreach, и добавляем его с вызовом метода pushProcessor в наш только что созданный процессор.

Теперь, когда все настроено, вы должны зарегистрировать этот проход компилятора в своем контейнере. Я предполагаю, что вы используете symfony 2.x, так что вы должны сделать это в своем AppBundle

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class AppBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        $container->addCompilerPass(new HandlerProcessorPass());
    }
}

Вот несколько дополнительных ссылок, которые могут быть полезны:

person Martin Parsiegla    schedule 29.05.2018