Symfony autowiring monolog渠道

Fab*_*pet 10 symfony monolog symfony-3.2

根据此文档,我可以创建许多通道,这些通道将使用以下名称创建服务monolog.logger.<channel_name>

如何通过DI注入和自动装配将这些服务注入我的服务?

class FooService
{
    public function __construct(LoggerInterface $loggerInterface) {  }
}
Run Code Online (Sandbox Code Playgroud)

YAML

#existing
foo_service:
    class: AppBundle\Services\FooService
    arguments: ["@monolog.logger.barchannel"]
# what I want to do
foo_service:
    autowire: true # how to inject @monolog.logger.barchannel ? 
Run Code Online (Sandbox Code Playgroud)

Dra*_*ter 9

我写了(也许更复杂)的方法.我不想标记我的自动服务,以告诉symfony使用哪个频道. 使用symfony 4与php 7.1.

我使用monolog.channels中定义的所有其他通道构建了LoggerFactory.

我的工厂是捆绑的,所以在Bundle.php中添加

$container->addCompilerPass(
    new LoggerFactoryPass(), 
    PassConfig::TYPE_BEFORE_OPTIMIZATION, 
    1
); // -1 call before monolog
Run Code Online (Sandbox Code Playgroud)

monolog.bundle之前调用此编译器是很重要的,因为传递后的monolog会从容器中删除参数.

现在,LoggerFactoryPass

namespace Bundle\DependencyInjection\Compiler;


use Bundle\Service\LoggerFactory;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class LoggerFactoryPass implements CompilerPassInterface
{

    /**
     * You can modify the container here before it is dumped to PHP code.
     * @param ContainerBuilder $container
     * @throws \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
     * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
     */
    public function process(ContainerBuilder $container): void
    {
        if (!$container->has(LoggerFactory::class) || !$container->hasDefinition('monolog.logger')) {
            return;
        }

        $definition = $container->findDefinition(LoggerFactory::class);
        foreach ($container->getParameter('monolog.additional_channels') as $channel) {
            $loggerId = sprintf('monolog.logger.%s', $channel);
            $definition->addMethodCall('addChannel', [
                $channel,
                new Reference($loggerId)
            ]);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和LoggerFactory

namespace Bundle\Service;

use Psr\Log\LoggerInterface;

class LoggerFactory
{
    protected $channels = [];

    public function addChannel($name, $loggerObject): void
    {
        $this->channels[$name] = $loggerObject;
    }

    /**
     * @param string $channel
     * @return LoggerInterface
     * @throws \InvalidArgumentException
     */
    public function getLogger(string $channel): LoggerInterface
    {
        if (!array_key_exists($channel, $this->channels)) {
            throw new \InvalidArgumentException('You are trying to reach not defined logger channel');
        }

        return $this->channels[$channel];
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,现在你可以注入LoggerFactory,并选择你的频道

public function acmeAction(LoggerFactory $factory)
{
    $logger = $factory->getLogger('my_channel');
    $logger->log('this is awesome!');
}
Run Code Online (Sandbox Code Playgroud)


num*_*web 8

您可以使用绑定参数

services:
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
        public: true
        bind:
            $loggerMyApi: '@monolog.logger.my_api'
Run Code Online (Sandbox Code Playgroud)

然后你可以在你的服务的构造函数中使用它:

use Psr\Log\LoggerInterface;
...
public function __construct(LoggerInterface $loggerMyApi)
{
...
}
Run Code Online (Sandbox Code Playgroud)


Tom*_*ski 7

经过一些搜索后,我发现了一些使用标签的解决方法,并手动将几个参数注入自动服务.

我的回答与@ Thomas-Landauer类似.不同的是,我不必手动创建记录器服务,因为编译器从monolog bundle传递给我做了这个.

services:
    _defaults:
        autowire: true
        autoconfigure: true
    AppBundle\Services\FooService:
        arguments:
            $loggerInterface: '@logger'
        tags:
            - { name: monolog.logger, channel: barchannel }
Run Code Online (Sandbox Code Playgroud)


fab*_*mlk 7

从MonologBu​​ndle 3.5开始,你可以通过自动装配不同的独白渠道类型暗示的语法如下服务参数:Psr\Log\LoggerInterface $<channel>Logger。例如,要注入与应用程序记录器通道相关的服务,请使用:

public function __construct(LoggerInterface $appLogger)
{
   $this->logger = $appLogger;
}
Run Code Online (Sandbox Code Playgroud)

https://symfony.com/doc/current/logging/channels_handlers.html#monolog-autowire-channels


Tho*_*uer 5

我没有找到自动连接记录器通道的方法。但是,我找到了一种autowire 原则上使用的方法,并且只手动注入记录器。使用您的class FooService,这就是services.yml(Symfony 3.3)的样子:

# services.yml

services:
    _defaults:
        autowire: true
        autoconfigure: true
    AppBundle\Services\FooService:
        arguments:
            $loggerInterface: '@monolog.logger.barchannel'
Run Code Online (Sandbox Code Playgroud)

所以“技巧”是显式注入记录器通道,同时仍然通过自动装配注入该服务的所有其他依赖项。