From 2148a0f33c078825b58d6b29d7a5c220abeb539a Mon Sep 17 00:00:00 2001 From: Erik van Velzen Date: Thu, 4 Jun 2020 04:28:00 +0200 Subject: [PATCH] Add priority field to processor tags So that the order in which the processors are used by monolog can be determined. --- .../Compiler/AddProcessorsPass.php | 61 +++++++++++++------ .../Compiler/AddProcessorsPassTest.php | 21 +++++++ 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/DependencyInjection/Compiler/AddProcessorsPass.php b/DependencyInjection/Compiler/AddProcessorsPass.php index 7afaa06c..728ca80d 100644 --- a/DependencyInjection/Compiler/AddProcessorsPass.php +++ b/DependencyInjection/Compiler/AddProcessorsPass.php @@ -28,32 +28,57 @@ 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'])); - } 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']; + } + ); + + 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['method'])) { - $processor = [new Reference($id), $tag['method']]; + if (!empty($tag['handler'])) { + $definition = $container->findDefinition(sprintf('monolog.handler.%s', $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 155e6cf0..02253ae5 100644 --- a/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php +++ b/Tests/DependencyInjection/Compiler/AddProcessorsPassTest.php @@ -34,6 +34,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]); } protected function getContainer() @@ -45,9 +52,11 @@ protected function getContainer() $definition = $container->getDefinition('monolog.logger_prototype'); $container->setDefinition('monolog.handler.test', new Definition('%monolog.handler.null.class%', [100, false])); $container->setDefinition('handler_test', new Definition('%monolog.handler.null.class%', [100, false])); + $container->setDefinition('monolog.handler.priority_test', new Definition('%monolog.handler.null.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']); @@ -57,6 +66,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());