diff --git a/CHANGELOG.md b/CHANGELOG.md index 18c6274a..6f6e912b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Migrate services configuration to PHP * Add `console.interactive_only` flag * Add `slack.exclude_fields` and `slackwebhook.exclude_fields` configuration +* Add a processor to all loggers only when tags do not specify a channel or handler ## 3.10.0 (2023-11-06) diff --git a/composer.json b/composer.json index 929cd677..c13fddb7 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,8 @@ "symfony/config": "^5.4 || ^6.0 || ^7.0", "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", - "symfony/monolog-bridge": "^5.4 || ^6.0 || ^7.0" + "symfony/monolog-bridge": "^5.4 || ^6.0 || ^7.0", + "symfony/polyfill-php84": "^1.30" }, "require-dev": { "symfony/console": "^5.4 || ^6.0 || ^7.0", diff --git a/src/DependencyInjection/Compiler/AddProcessorsPass.php b/src/DependencyInjection/Compiler/AddProcessorsPass.php index cc99b67d..e325ea16 100644 --- a/src/DependencyInjection/Compiler/AddProcessorsPass.php +++ b/src/DependencyInjection/Compiler/AddProcessorsPass.php @@ -32,6 +32,10 @@ public function process(ContainerBuilder $container) } foreach ($container->findTaggedServiceIds('monolog.processor') as $id => $tags) { + if (array_any($tags, $closure = function (array $tag) { return (bool) $tag; })) { + $tags = array_filter($tags, $closure); + } + foreach ($tags as $tag) { if (!empty($tag['channel']) && !empty($tag['handler'])) { throw new \InvalidArgumentException(\sprintf('you cannot specify both the "handler" and "channel" attributes for the "monolog.processor" tag on service "%s"', $id)); diff --git a/tests/DependencyInjection/Compiler/AddProcessorsPassTest.php b/tests/DependencyInjection/Compiler/AddProcessorsPassTest.php index b1ef9de6..8d3eee41 100644 --- a/tests/DependencyInjection/Compiler/AddProcessorsPassTest.php +++ b/tests/DependencyInjection/Compiler/AddProcessorsPassTest.php @@ -16,7 +16,10 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Handler\ConsoleHandler; use Symfony\Bundle\MonologBundle\DependencyInjection\Compiler\AddProcessorsPass; +use Symfony\Bundle\MonologBundle\DependencyInjection\Compiler\LoggerChannelPass; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\Compiler\PassConfig; +use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; @@ -65,6 +68,58 @@ public function testFailureOnHandlerWithoutPushProcessor() } } + /** + * @dataProvider provideEmptyTagsData + */ + public function testEmptyTagsAreIgnoredWhenNonEmptyArePresent(array $tagAttributesList, array $expectedLoggerCalls, array $expectedMyChannelLoggerCalls) + { + $container = new ContainerBuilder(); + $loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../../../config')); + $loader->load('monolog.php'); + + $container->setParameter('monolog.additional_channels', ['my_channel']); + $container->setParameter('monolog.handlers_to_channels', []); + + $container->register('TestClass')->setTags(['monolog.processor' => $tagAttributesList]); + + $container->getCompilerPassConfig()->setOptimizationPasses([]); + $container->getCompilerPassConfig()->setRemovingPasses([]); + $container->addCompilerPass(new ResolveChildDefinitionsPass(), PassConfig::TYPE_OPTIMIZE); + $container->addCompilerPass(new LoggerChannelPass()); + $container->addCompilerPass(new AddProcessorsPass()); + $container->compile(); + + $this->assertEquals($expectedLoggerCalls, $container->getDefinition('monolog.logger')->getMethodCalls()); + $this->assertEquals($expectedMyChannelLoggerCalls, $container->getDefinition('monolog.logger.my_channel')->getMethodCalls()); + } + + public static function provideEmptyTagsData(): iterable + { + yield 'with empty tag' => [ + [[]], + [['pushProcessor', [new Reference('TestClass')]], ['useMicrosecondTimestamps', ['%monolog.use_microseconds%']]], + [['pushProcessor', [new Reference('TestClass')]]], + ]; + + yield 'with app channel' => [ + [[], ['channel' => 'app']], + [['useMicrosecondTimestamps', ['%monolog.use_microseconds%']], ['pushProcessor', [new Reference('TestClass')]]], + [], + ]; + + yield 'with my_channel channel' => [ + [[], ['channel' => 'my_channel']], + [['useMicrosecondTimestamps', ['%monolog.use_microseconds%']]], + [['pushProcessor', [new Reference('TestClass')]]], + ]; + + yield 'with method and no channel' => [ + [[], ['method' => 'foo']], + [['pushProcessor', [[new Reference('TestClass'), 'foo']]], ['useMicrosecondTimestamps', ['%monolog.use_microseconds%']]], + [['pushProcessor', [[new Reference('TestClass'), 'foo']]]], + ]; + } + protected function getContainer() { $container = new ContainerBuilder();