From ea0845769fc00bc78927478a604651179eeeee31 Mon Sep 17 00:00:00 2001 From: Roy Date: Fri, 17 Mar 2023 13:12:04 +0100 Subject: [PATCH 1/6] Add priority field to processor tags So that the order in which the processors are used by monolog can be determined. --- .../Compiler/AddProcessorsPass.php | 77 ++++++++++++------- .../Compiler/AddProcessorsPassTest.php | 21 +++++ 2 files changed, 72 insertions(+), 26 deletions(-) diff --git a/DependencyInjection/Compiler/AddProcessorsPass.php b/DependencyInjection/Compiler/AddProcessorsPass.php index cc99b67d..884f930e 100644 --- a/DependencyInjection/Compiler/AddProcessorsPass.php +++ b/DependencyInjection/Compiler/AddProcessorsPass.php @@ -31,40 +31,65 @@ public function process(ContainerBuilder $container) return; } + $processors = []; + foreach ($container->findTaggedServiceIds('monolog.processor') as $id => $tags) { 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)); + if (!isset($tag['priority'])) { + $tag['priority'] = 0; } - if (!empty($tag['handler'])) { - $definition = $container->findDefinition(\sprintf('monolog.handler.%s', $tag['handler'])); - $parentDef = $definition; - while (!$parentDef->getClass() && $parentDef instanceof ChildDefinition) { - $parentDef = $container->findDefinition($parentDef->getParent()); - } - $class = $container->getParameterBag()->resolveValue($parentDef->getClass()); - if (!method_exists($class, 'pushProcessor')) { - throw new \InvalidArgumentException(\sprintf('The "%s" handler does not accept processors', $tag['handler'])); - } - } elseif (!empty($tag['channel'])) { - if ('app' === $tag['channel']) { - $definition = $container->getDefinition('monolog.logger'); - } else { - $definition = $container->getDefinition(\sprintf('monolog.logger.%s', $tag['channel'])); - } - } else { - $definition = $container->getDefinition('monolog.logger_prototype'); - } + $processors[] = [ + 'id' => $id, + 'tag' => $tag, + ]; + } + } + + // Sort by priority so that higher-prio processors are added last. + // The effect is the monolog will call the higher-prio processors first + usort( + $processors, + function (array $left, array $right) { + return $left['tag']['priority'] - $right['tag']['priority']; + } + ); - if (!empty($tag['method'])) { - $processor = [new Reference($id), $tag['method']]; + foreach ($processors as $processor) { + $tag = $processor['tag']; + $id = $processor['id']; + + 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)); + } + + if (!empty($tag['handler'])) { + $definition = $container->findDefinition(sprintf('monolog.handler.%s', $tag['handler'])); + $parentDef = $definition; + while (!$parentDef->getClass() && $parentDef instanceof ChildDefinition) { + $parentDef = $container->findDefinition($parentDef->getParent()); + } + $class = $container->getParameterBag()->resolveValue($parentDef->getClass()); + if (!method_exists($class, 'pushProcessor')) { + throw new \InvalidArgumentException(sprintf('The "%s" handler does not accept processors', $tag['handler'])); + } + } elseif (!empty($tag['channel'])) { + if ('app' === $tag['channel']) { + $definition = $container->getDefinition('monolog.logger'); } else { - // If no method is defined, fallback to use __invoke - $processor = new Reference($id); + $definition = $container->getDefinition(sprintf('monolog.logger.%s', $tag['channel'])); } - $definition->addMethodCall('pushProcessor', [$processor]); + } else { + $definition = $container->getDefinition('monolog.logger_prototype'); + } + + if (!empty($tag['method'])) { + $processor = [new Reference($id), $tag['method']]; + } else { + // If no method is defined, fallback to use __invoke + $processor = new Reference($id); } + $definition->addMethodCall('pushProcessor', [$processor]); } } } diff --git a/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php b/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php index ada24c8f..30aee64e 100644 --- a/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php +++ b/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php @@ -37,6 +37,13 @@ public function testHandlerProcessors() $calls = $service->getMethodCalls(); $this->assertCount(1, $calls); $this->assertEquals(['pushProcessor', [new Reference('test2')]], $calls[0]); + + $service = $container->getDefinition('monolog.handler.priority_test'); + $calls = $service->getMethodCalls(); + $this->assertCount(3, $calls); + $this->assertEquals(['pushProcessor', [new Reference('processor-10')]], $calls[0]); + $this->assertEquals(['pushProcessor', [new Reference('processor+10')]], $calls[1]); + $this->assertEquals(['pushProcessor', [new Reference('processor+20')]], $calls[2]); } public function testFailureOnHandlerWithoutPushProcessor() @@ -75,9 +82,11 @@ protected function getContainer() $container->setParameter('monolog.handler.console.class', ConsoleHandler::class); $container->setDefinition('monolog.handler.test', new Definition('%monolog.handler.console.class%', [100, false])); $container->setDefinition('handler_test', new Definition('%monolog.handler.console.class%', [100, false])); + $container->setDefinition('monolog.handler.priority_test', new Definition('%monolog.handler.console.class%', [100, false])); $container->setAlias('monolog.handler.test2', 'handler_test'); $definition->addMethodCall('pushHandler', [new Reference('monolog.handler.test')]); $definition->addMethodCall('pushHandler', [new Reference('monolog.handler.test2')]); + $definition->addMethodCall('pushHandler', [new Reference('monolog.handler.priority_test')]); $service = new Definition('TestClass', ['false', new Reference('logger')]); $service->addTag('monolog.processor', ['handler' => 'test']); @@ -87,6 +96,18 @@ protected function getContainer() $service->addTag('monolog.processor', ['handler' => 'test2']); $container->setDefinition('test2', $service); + $service = new Definition('TestClass', ['false', new Reference('logger')]); + $service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 10]); + $container->setDefinition('processor+10', $service); + + $service = new Definition('TestClass', ['false', new Reference('logger')]); + $service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => -10]); + $container->setDefinition('processor-10', $service); + + $service = new Definition('TestClass', ['false', new Reference('logger')]); + $service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 20]); + $container->setDefinition('processor+20', $service); + $container->getCompilerPassConfig()->setOptimizationPasses([]); $container->getCompilerPassConfig()->setRemovingPasses([]); $container->addCompilerPass(new AddProcessorsPass()); From 39ff3bd05337fa0a0a7f4da4e88076339434a603 Mon Sep 17 00:00:00 2001 From: Roy Date: Mon, 20 Mar 2023 08:33:10 +0100 Subject: [PATCH 2/6] spaceship! --- DependencyInjection/Compiler/AddProcessorsPass.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DependencyInjection/Compiler/AddProcessorsPass.php b/DependencyInjection/Compiler/AddProcessorsPass.php index 884f930e..e8bb60c2 100644 --- a/DependencyInjection/Compiler/AddProcessorsPass.php +++ b/DependencyInjection/Compiler/AddProcessorsPass.php @@ -51,7 +51,7 @@ public function process(ContainerBuilder $container) usort( $processors, function (array $left, array $right) { - return $left['tag']['priority'] - $right['tag']['priority']; + return $left['tag']['priority'] <=> $right['tag']['priority']; } ); From 32e6cc7a226f6159fc50e0bdf6ea71bbea731a8e Mon Sep 17 00:00:00 2001 From: HypeMC Date: Sun, 28 Jul 2024 21:29:41 +0200 Subject: [PATCH 3/6] Use `PriorityTaggedServiceTrait` --- .../Compiler/AddProcessorsPass.php | 83 +++++++------------ 1 file changed, 31 insertions(+), 52 deletions(-) diff --git a/DependencyInjection/Compiler/AddProcessorsPass.php b/DependencyInjection/Compiler/AddProcessorsPass.php index e8bb60c2..f44f81e5 100644 --- a/DependencyInjection/Compiler/AddProcessorsPass.php +++ b/DependencyInjection/Compiler/AddProcessorsPass.php @@ -13,8 +13,8 @@ use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; /** * Registers processors in Monolog loggers or handlers. @@ -25,71 +25,50 @@ */ class AddProcessorsPass implements CompilerPassInterface { + use PriorityTaggedServiceTrait; + public function process(ContainerBuilder $container) { if (!$container->hasDefinition('monolog.logger')) { return; } - $processors = []; + foreach (array_reverse($this->findAndSortTaggedServices('monolog.processor', $container)) as $reference) { + $tags = $container->getDefinition((string) $reference)->getTag('monolog.processor'); - foreach ($container->findTaggedServiceIds('monolog.processor') as $id => $tags) { foreach ($tags as $tag) { - if (!isset($tag['priority'])) { - $tag['priority'] = 0; + 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"', $reference)); } - $processors[] = [ - 'id' => $id, - 'tag' => $tag, - ]; - } - } - - // Sort by priority so that higher-prio processors are added last. - // The effect is the monolog will call the higher-prio processors first - usort( - $processors, - function (array $left, array $right) { - return $left['tag']['priority'] <=> $right['tag']['priority']; - } - ); - - foreach ($processors as $processor) { - $tag = $processor['tag']; - $id = $processor['id']; - - 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)); - } - - if (!empty($tag['handler'])) { - $definition = $container->findDefinition(sprintf('monolog.handler.%s', $tag['handler'])); - $parentDef = $definition; - while (!$parentDef->getClass() && $parentDef instanceof ChildDefinition) { - $parentDef = $container->findDefinition($parentDef->getParent()); - } - $class = $container->getParameterBag()->resolveValue($parentDef->getClass()); - if (!method_exists($class, 'pushProcessor')) { - throw new \InvalidArgumentException(sprintf('The "%s" handler does not accept processors', $tag['handler'])); - } - } elseif (!empty($tag['channel'])) { - if ('app' === $tag['channel']) { - $definition = $container->getDefinition('monolog.logger'); + if (!empty($tag['handler'])) { + $definition = $container->findDefinition(\sprintf('monolog.handler.%s', $tag['handler'])); + $parentDef = $definition; + while (!$parentDef->getClass() && $parentDef instanceof ChildDefinition) { + $parentDef = $container->findDefinition($parentDef->getParent()); + } + $class = $container->getParameterBag()->resolveValue($parentDef->getClass()); + if (!method_exists($class, 'pushProcessor')) { + throw new \InvalidArgumentException(\sprintf('The "%s" handler does not accept processors', $tag['handler'])); + } + } elseif (!empty($tag['channel'])) { + if ('app' === $tag['channel']) { + $definition = $container->getDefinition('monolog.logger'); + } else { + $definition = $container->getDefinition(\sprintf('monolog.logger.%s', $tag['channel'])); + } } else { - $definition = $container->getDefinition(sprintf('monolog.logger.%s', $tag['channel'])); + $definition = $container->getDefinition('monolog.logger_prototype'); } - } else { - $definition = $container->getDefinition('monolog.logger_prototype'); - } - if (!empty($tag['method'])) { - $processor = [new Reference($id), $tag['method']]; - } else { - // If no method is defined, fallback to use __invoke - $processor = new Reference($id); + if (!empty($tag['method'])) { + $processor = [$reference, $tag['method']]; + } else { + // If no method is defined, fallback to use __invoke + $processor = $reference; + } + $definition->addMethodCall('pushProcessor', [$processor]); } - $definition->addMethodCall('pushProcessor', [$processor]); } } } From 28d9bcc38c7f182e0df9052846845c17bbd862f5 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Tue, 6 Aug 2024 12:14:01 +0200 Subject: [PATCH 4/6] Add comment --- DependencyInjection/Compiler/AddProcessorsPass.php | 1 + 1 file changed, 1 insertion(+) diff --git a/DependencyInjection/Compiler/AddProcessorsPass.php b/DependencyInjection/Compiler/AddProcessorsPass.php index f44f81e5..b42b5929 100644 --- a/DependencyInjection/Compiler/AddProcessorsPass.php +++ b/DependencyInjection/Compiler/AddProcessorsPass.php @@ -33,6 +33,7 @@ public function process(ContainerBuilder $container) return; } + // array_reverse is used because ProcessableHandlerTrait::pushProcessor prepends processors to the beginning of the stack foreach (array_reverse($this->findAndSortTaggedServices('monolog.processor', $container)) as $reference) { $tags = $container->getDefinition((string) $reference)->getTag('monolog.processor'); From be95b647dbba547b2206f6ce069da9a77e36329d Mon Sep 17 00:00:00 2001 From: HypeMC Date: Tue, 8 Oct 2024 17:10:47 +0200 Subject: [PATCH 5/6] Fix for multiple tags --- .../Compiler/AddProcessorsPass.php | 72 +++++++++++-------- .../Compiler/AddProcessorsPassTest.php | 34 +++++++-- 2 files changed, 70 insertions(+), 36 deletions(-) diff --git a/DependencyInjection/Compiler/AddProcessorsPass.php b/DependencyInjection/Compiler/AddProcessorsPass.php index b42b5929..5c276a9d 100644 --- a/DependencyInjection/Compiler/AddProcessorsPass.php +++ b/DependencyInjection/Compiler/AddProcessorsPass.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\MonologBundle\DependencyInjection\Compiler; +use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; @@ -33,43 +34,54 @@ public function process(ContainerBuilder $container) return; } + $indexedTags = []; + $i = 1; + + foreach ($container->findTaggedServiceIds('monolog.processor') as $id => $tags) { + foreach ($tags as &$tag) { + $indexedTags[$tag['index'] = $i++] = $tag; + } + unset($tag); + $definition = $container->getDefinition($id); + $definition->setTags(array_merge($definition->getTags(), ['monolog.processor' => $tags])); + } + + $taggedIteratorArgument = new TaggedIteratorArgument('monolog.processor', 'index', null, true); // array_reverse is used because ProcessableHandlerTrait::pushProcessor prepends processors to the beginning of the stack - foreach (array_reverse($this->findAndSortTaggedServices('monolog.processor', $container)) as $reference) { - $tags = $container->getDefinition((string) $reference)->getTag('monolog.processor'); + foreach (array_reverse($this->findAndSortTaggedServices($taggedIteratorArgument, $container), true) as $index => $reference) { + $tag = $indexedTags[$index]; - 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"', $reference)); - } + 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"', $reference)); + } - if (!empty($tag['handler'])) { - $definition = $container->findDefinition(\sprintf('monolog.handler.%s', $tag['handler'])); - $parentDef = $definition; - while (!$parentDef->getClass() && $parentDef instanceof ChildDefinition) { - $parentDef = $container->findDefinition($parentDef->getParent()); - } - $class = $container->getParameterBag()->resolveValue($parentDef->getClass()); - if (!method_exists($class, 'pushProcessor')) { - throw new \InvalidArgumentException(\sprintf('The "%s" handler does not accept processors', $tag['handler'])); - } - } elseif (!empty($tag['channel'])) { - if ('app' === $tag['channel']) { - $definition = $container->getDefinition('monolog.logger'); - } else { - $definition = $container->getDefinition(\sprintf('monolog.logger.%s', $tag['channel'])); - } - } else { - $definition = $container->getDefinition('monolog.logger_prototype'); + if (!empty($tag['handler'])) { + $definition = $container->findDefinition(\sprintf('monolog.handler.%s', $tag['handler'])); + $parentDef = $definition; + while (!$parentDef->getClass() && $parentDef instanceof ChildDefinition) { + $parentDef = $container->findDefinition($parentDef->getParent()); } - - if (!empty($tag['method'])) { - $processor = [$reference, $tag['method']]; + $class = $container->getParameterBag()->resolveValue($parentDef->getClass()); + if (!method_exists($class, 'pushProcessor')) { + throw new \InvalidArgumentException(\sprintf('The "%s" handler does not accept processors', $tag['handler'])); + } + } elseif (!empty($tag['channel'])) { + if ('app' === $tag['channel']) { + $definition = $container->getDefinition('monolog.logger'); } else { - // If no method is defined, fallback to use __invoke - $processor = $reference; + $definition = $container->getDefinition(\sprintf('monolog.logger.%s', $tag['channel'])); } - $definition->addMethodCall('pushProcessor', [$processor]); + } else { + $definition = $container->getDefinition('monolog.logger_prototype'); + } + + if (!empty($tag['method'])) { + $processor = [$reference, $tag['method']]; + } else { + // If no method is defined, fallback to use __invoke + $processor = $reference; } + $definition->addMethodCall('pushProcessor', [$processor]); } } } diff --git a/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php b/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php index 30aee64e..b1cb82d0 100644 --- a/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php +++ b/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php @@ -21,6 +21,7 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\TypedReference; class AddProcessorsPassTest extends TestCase { @@ -31,19 +32,28 @@ public function testHandlerProcessors() $service = $container->getDefinition('monolog.handler.test'); $calls = $service->getMethodCalls(); $this->assertCount(1, $calls); - $this->assertEquals(['pushProcessor', [new Reference('test')]], $calls[0]); + $this->assertEquals(['pushProcessor', [new TypedReference('test', 'TestClass')]], $calls[0]); $service = $container->getDefinition('handler_test'); $calls = $service->getMethodCalls(); $this->assertCount(1, $calls); - $this->assertEquals(['pushProcessor', [new Reference('test2')]], $calls[0]); + $this->assertEquals(['pushProcessor', [new TypedReference('test2', 'TestClass')]], $calls[0]); $service = $container->getDefinition('monolog.handler.priority_test'); $calls = $service->getMethodCalls(); - $this->assertCount(3, $calls); - $this->assertEquals(['pushProcessor', [new Reference('processor-10')]], $calls[0]); - $this->assertEquals(['pushProcessor', [new Reference('processor+10')]], $calls[1]); - $this->assertEquals(['pushProcessor', [new Reference('processor+20')]], $calls[2]); + $this->assertCount(5, $calls); + $this->assertEquals(['pushProcessor', [new TypedReference('processor-10', 'TestClass')]], $calls[0]); + $this->assertEquals(['pushProcessor', [new TypedReference('processor+10', 'TestClass')]], $calls[1]); + $this->assertEquals(['pushProcessor', [new TypedReference('processor+20', 'TestClass')]], $calls[2]); + $this->assertEquals(['pushProcessor', [new TypedReference('processor+20', 'TestClass')]], $calls[2]); + $this->assertEquals(['pushProcessor', [new TypedReference('processor+25+35', 'TestClass')]], $calls[3]); + $this->assertEquals(['pushProcessor', [new TypedReference('processor+35+25', 'TestClass')]], $calls[4]); + + $service = $container->getDefinition('monolog.handler.priority_test_2'); + $calls = $service->getMethodCalls(); + $this->assertCount(2, $calls); + $this->assertEquals(['pushProcessor', [new TypedReference('processor+35+25', 'TestClass')]], $calls[0]); + $this->assertEquals(['pushProcessor', [new TypedReference('processor+25+35', 'TestClass')]], $calls[1]); } public function testFailureOnHandlerWithoutPushProcessor() @@ -83,10 +93,12 @@ protected function getContainer() $container->setDefinition('monolog.handler.test', new Definition('%monolog.handler.console.class%', [100, false])); $container->setDefinition('handler_test', new Definition('%monolog.handler.console.class%', [100, false])); $container->setDefinition('monolog.handler.priority_test', new Definition('%monolog.handler.console.class%', [100, false])); + $container->setDefinition('monolog.handler.priority_test_2', new Definition('%monolog.handler.console.class%', [100, false])); $container->setAlias('monolog.handler.test2', 'handler_test'); $definition->addMethodCall('pushHandler', [new Reference('monolog.handler.test')]); $definition->addMethodCall('pushHandler', [new Reference('monolog.handler.test2')]); $definition->addMethodCall('pushHandler', [new Reference('monolog.handler.priority_test')]); + $definition->addMethodCall('pushHandler', [new Reference('monolog.handler.priority_test_2')]); $service = new Definition('TestClass', ['false', new Reference('logger')]); $service->addTag('monolog.processor', ['handler' => 'test']); @@ -108,6 +120,16 @@ protected function getContainer() $service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 20]); $container->setDefinition('processor+20', $service); + $service = new Definition('TestClass', ['false', new Reference('logger')]); + $service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 35]); + $service->addTag('monolog.processor', ['handler' => 'priority_test_2', 'priority' => 25]); + $container->setDefinition('processor+35+25', $service); + + $service = new Definition('TestClass', ['false', new Reference('logger')]); + $service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 25]); + $service->addTag('monolog.processor', ['handler' => 'priority_test_2', 'priority' => 35]); + $container->setDefinition('processor+25+35', $service); + $container->getCompilerPassConfig()->setOptimizationPasses([]); $container->getCompilerPassConfig()->setRemovingPasses([]); $container->addCompilerPass(new AddProcessorsPass()); From 5c3db6c84b2fcc7e7788bf779b0131d175ec0a49 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Fri, 22 Aug 2025 02:22:38 +0200 Subject: [PATCH 6/6] Fix priority with logger_prototype --- .../Compiler/AddProcessorsPass.php | 30 ++++++++++---- MonologBundle.php | 2 +- .../Compiler/AddProcessorsPassTest.php | 41 +++++++++++++++---- 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/DependencyInjection/Compiler/AddProcessorsPass.php b/DependencyInjection/Compiler/AddProcessorsPass.php index 5c276a9d..530af802 100644 --- a/DependencyInjection/Compiler/AddProcessorsPass.php +++ b/DependencyInjection/Compiler/AddProcessorsPass.php @@ -28,6 +28,13 @@ class AddProcessorsPass implements CompilerPassInterface { use PriorityTaggedServiceTrait; + private $channelPass; + + public function __construct(?LoggerChannelPass $channelPass = null) + { + $this->channelPass = $channelPass; + } + public function process(ContainerBuilder $container) { if (!$container->hasDefinition('monolog.logger')) { @@ -56,8 +63,8 @@ public function process(ContainerBuilder $container) } if (!empty($tag['handler'])) { - $definition = $container->findDefinition(\sprintf('monolog.handler.%s', $tag['handler'])); - $parentDef = $definition; + $parentDef = $container->findDefinition(\sprintf('monolog.handler.%s', $tag['handler'])); + $definitions = [$parentDef]; while (!$parentDef->getClass() && $parentDef instanceof ChildDefinition) { $parentDef = $container->findDefinition($parentDef->getParent()); } @@ -66,13 +73,18 @@ public function process(ContainerBuilder $container) throw new \InvalidArgumentException(\sprintf('The "%s" handler does not accept processors', $tag['handler'])); } } elseif (!empty($tag['channel'])) { - if ('app' === $tag['channel']) { - $definition = $container->getDefinition('monolog.logger'); + $loggerId = 'app' === $tag['channel'] ? 'monolog.logger' : \sprintf('monolog.logger.%s', $tag['channel']); + $definitions = [$container->getDefinition($loggerId)]; + } else { + if ($this->channelPass) { + $definitions = []; + foreach ($this->channelPass->getChannels() as $channel) { + $loggerId = 'app' === $channel ? 'monolog.logger' : \sprintf('monolog.logger.%s', $channel); + $definitions[] = $container->getDefinition($loggerId); + } } else { - $definition = $container->getDefinition(\sprintf('monolog.logger.%s', $tag['channel'])); + $definitions = [$container->getDefinition('monolog.logger_prototype')]; } - } else { - $definition = $container->getDefinition('monolog.logger_prototype'); } if (!empty($tag['method'])) { @@ -81,7 +93,9 @@ public function process(ContainerBuilder $container) // If no method is defined, fallback to use __invoke $processor = $reference; } - $definition->addMethodCall('pushProcessor', [$processor]); + foreach ($definitions as $definition) { + $definition->addMethodCall('pushProcessor', [$processor]); + } } } } diff --git a/MonologBundle.php b/MonologBundle.php index baae67f2..dc57a791 100644 --- a/MonologBundle.php +++ b/MonologBundle.php @@ -37,7 +37,7 @@ public function build(ContainerBuilder $container) $container->addCompilerPass($channelPass = new LoggerChannelPass()); $container->addCompilerPass(new FixEmptyLoggerPass($channelPass)); - $container->addCompilerPass(new AddProcessorsPass()); + $container->addCompilerPass(new AddProcessorsPass($channelPass)); $container->addCompilerPass(new AddSwiftMailerTransportPass()); } diff --git a/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php b/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php index b1cb82d0..284e5fea 100644 --- a/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php +++ b/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php @@ -16,6 +16,7 @@ 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\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; @@ -54,6 +55,18 @@ public function testHandlerProcessors() $this->assertCount(2, $calls); $this->assertEquals(['pushProcessor', [new TypedReference('processor+35+25', 'TestClass')]], $calls[0]); $this->assertEquals(['pushProcessor', [new TypedReference('processor+25+35', 'TestClass')]], $calls[1]); + + $service = $container->getDefinition('monolog.logger'); + $calls = $service->getMethodCalls(); + $this->assertCount(2, $calls); + $this->assertEquals(['useMicrosecondTimestamps', ['%monolog.use_microseconds%']], $calls[0]); + $this->assertEquals(['pushProcessor', [new TypedReference('processor_all_channels+0', 'TestClass')]], $calls[1]); + + $service = $container->getDefinition('monolog.logger.test'); + $calls = $service->getMethodCalls(); + $this->assertCount(2, $calls); + $this->assertEquals(['pushProcessor', [new TypedReference('processor_test_channel-25', 'TestClass')]], $calls[0]); + $this->assertEquals(['pushProcessor', [new TypedReference('processor_all_channels+0', 'TestClass')]], $calls[1]); } public function testFailureOnHandlerWithoutPushProcessor() @@ -88,6 +101,9 @@ protected function getContainer() $loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../../../Resources/config')); $loader->load('monolog.php'); + $container->setParameter('monolog.additional_channels', ['test']); + $container->setParameter('monolog.handlers_to_channels', []); + $definition = $container->getDefinition('monolog.logger_prototype'); $container->setParameter('monolog.handler.console.class', ConsoleHandler::class); $container->setDefinition('monolog.handler.test', new Definition('%monolog.handler.console.class%', [100, false])); @@ -100,39 +116,48 @@ protected function getContainer() $definition->addMethodCall('pushHandler', [new Reference('monolog.handler.priority_test')]); $definition->addMethodCall('pushHandler', [new Reference('monolog.handler.priority_test_2')]); - $service = new Definition('TestClass', ['false', new Reference('logger')]); + $service = new Definition('TestClass'); $service->addTag('monolog.processor', ['handler' => 'test']); $container->setDefinition('test', $service); - $service = new Definition('TestClass', ['false', new Reference('logger')]); + $service = new Definition('TestClass'); $service->addTag('monolog.processor', ['handler' => 'test2']); $container->setDefinition('test2', $service); - $service = new Definition('TestClass', ['false', new Reference('logger')]); + $service = new Definition('TestClass'); $service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 10]); $container->setDefinition('processor+10', $service); - $service = new Definition('TestClass', ['false', new Reference('logger')]); + $service = new Definition('TestClass'); $service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => -10]); $container->setDefinition('processor-10', $service); - $service = new Definition('TestClass', ['false', new Reference('logger')]); + $service = new Definition('TestClass'); $service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 20]); $container->setDefinition('processor+20', $service); - $service = new Definition('TestClass', ['false', new Reference('logger')]); + $service = new Definition('TestClass'); $service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 35]); $service->addTag('monolog.processor', ['handler' => 'priority_test_2', 'priority' => 25]); $container->setDefinition('processor+35+25', $service); - $service = new Definition('TestClass', ['false', new Reference('logger')]); + $service = new Definition('TestClass'); $service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 25]); $service->addTag('monolog.processor', ['handler' => 'priority_test_2', 'priority' => 35]); $container->setDefinition('processor+25+35', $service); + $service = new Definition('TestClass'); + $service->addTag('monolog.processor', ['priority' => 0]); + $container->setDefinition('processor_all_channels+0', $service); + + $service = new Definition('TestClass'); + $service->addTag('monolog.processor', ['channel' => 'test', 'priority' => -25]); + $container->setDefinition('processor_test_channel-25', $service); + $container->getCompilerPassConfig()->setOptimizationPasses([]); $container->getCompilerPassConfig()->setRemovingPasses([]); - $container->addCompilerPass(new AddProcessorsPass()); + $container->addCompilerPass($channelPass = new LoggerChannelPass()); + $container->addCompilerPass(new AddProcessorsPass($channelPass)); $container->compile(); return $container;