Symfony autowiring monolog channels
I wrote (maybe more complicated) method. I don't want to tag my autowired services to tell symfony which channel to use. Using symfony 4 with php 7.1.
I built LoggerFactory with all additional channels defined in monolog.channels.
My factory is in bundle, so in Bundle.php add
$container->addCompilerPass( new LoggerFactoryPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 1); // -1 call before monolog
This is important to call this compiler pass before monolog.bundle because monolog after pass removes parameters from container.
Now, 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) ]); } }}
and 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]; }}
So, now you can inject LoggerFactory, and choose your channel
public function acmeAction(LoggerFactory $factory){ $logger = $factory->getLogger('my_channel'); $logger->log('this is awesome!');}
After some searching I have found some kind of workaround using tags and manually injecting several parameters to autowired service.
My answer looks similar to @Thomas-Landauer. The difference is, I do not have to manually create logger service, as the compiler pass from monolog bundle does this for me.
services: _defaults: autowire: true autoconfigure: true AppBundle\Services\FooService: arguments: $loggerInterface: '@logger' tags: - { name: monolog.logger, channel: barchannel }
You can use the bind parameter:
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'
Then you can use it in your service's constructor:
use Psr\Log\LoggerInterface;...public function __construct(LoggerInterface $loggerMyApi){...}