Ver código fonte

Added support for different channels through tags

All channels will use the same handlers but a different channel name.
This allows to easily know which part of the application generated this
message.
Christophe Coevoet 14 anos atrás
pai
commit
327d311b56

+ 59 - 0
src/Symfony/Bundle/MonologBundle/DependencyInjection/Compiler/LoggerChannelPass.php

@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\MonologBundle\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\DefinitionDecorator;
+
+/**
+ * Replaces the default logger by another one with its own channel for tagged services.
+ *
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+class LoggerChannelPass implements CompilerPassInterface
+{
+    protected $channels = array();
+
+    public function process(ContainerBuilder $container)
+    {
+        if (false === $container->hasDefinition('monolog.logger')) {
+            return;
+        }
+
+        foreach ($container->findTaggedServiceIds('monolog.logger') as $id => $tags) {
+            foreach ($tags as $tag) {
+                if (!empty ($tag['channel']) && 'app' !== $tag['channel']) {
+                    $definition = $container->getDefinition($id);
+                    $loggerId = sprintf('monolog.logger.%s', $tag['channel']);
+                    $this->createLogger($tag['channel'], $loggerId, $container);
+                    foreach ($definition->getArguments() as $index => $argument) {
+                        if ($argument instanceof Reference && 'logger' === (string) $argument) {
+                            $definition->setArgument($index, new Reference($loggerId, $argument->getInvalidBehavior(), $argument->isStrict()));
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    protected function createLogger($channel, $loggerId, ContainerBuilder $container)
+    {
+        if (!in_array($channel, $this->channels)) {
+            $logger = new DefinitionDecorator('monolog.logger_prototype');
+            $logger->setArgument(0, $channel);
+            $container->setDefinition($loggerId, $logger);
+            array_push($this->channels, $channel);
+        }
+    }
+}

+ 9 - 7
src/Symfony/Bundle/MonologBundle/DependencyInjection/MonologExtension.php

@@ -52,25 +52,26 @@ class MonologExtension extends Extension
             $loader->load('monolog.xml');
             $container->setAlias('logger', 'monolog.logger');
 
-            $logger = $container->getDefinition('monolog.logger');
+            $logger = $container->getDefinition('monolog.logger.prototype');
 
             $handlers = array();
-            foreach ($config['handlers'] as $handler) {
-                $handlers[] = $this->buildHandler($container, $handler);
+            foreach ($config['handlers'] as $name => $handler) {
+                $handlers[] = $this->buildHandler($container, $name, $handler);
             }
 
             // TODO somehow the DebugLogger should be pushed on the stack as well, or that concept needs to be changed
             // didn't have to investigate yet what it is exactly
             $handlers = array_reverse($handlers);
             foreach ($handlers as $handler) {
-                $logger->addMethodCall('pushHandler', array($handler));
+                $logger->addMethodCall('pushHandler', array(new Reference($handler)));
             }
         }
     }
 
-    public function buildHandler(ContainerBuilder $container, array $handler)
+    public function buildHandler(ContainerBuilder $container, $name, array $handler)
     {
-        $definition = new Definition(new Parameter('monolog.handler.'.$handler['type'].'.class'));
+        $handlerId = sprintf('monolog.handler.%s', $name);
+        $definition = new Definition(sprintf('%monolog.handler.%s.class%', $handler['type']));
         $handler['level'] = is_int($handler['level']) ? $handler['level'] : constant('Monolog\Logger::'.strtoupper($handler['level']));
 
         switch ($handler['type']) {
@@ -107,8 +108,9 @@ class MonologExtension extends Extension
             ));
             break;
         }
+        $container->setDefinition($handlerId, $definition);
 
-        return $definition;
+        return $handlerId;
     }
 
     /**

+ 8 - 0
src/Symfony/Bundle/MonologBundle/MonologBundle.php

@@ -12,6 +12,8 @@
 namespace Symfony\Bundle\MonologBundle;
 
 use Symfony\Component\HttpKernel\Bundle\Bundle;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Bundle\MonologBundle\DependencyInjection\Compiler\LoggerChannelPass;
 
 /**
  * Bundle.
@@ -20,4 +22,10 @@ use Symfony\Component\HttpKernel\Bundle\Bundle;
  */
 class MonologBundle extends Bundle
 {
+    public function build(ContainerBuilder $container)
+    {
+        parent::build($container);
+
+        $container->addCompilerPass(new LoggerChannelPass());
+    }
 }

+ 5 - 2
src/Symfony/Bundle/MonologBundle/Resources/config/monolog.xml

@@ -13,8 +13,11 @@
     </parameters>
 
     <services>
-        <service id="monolog.logger" class="%monolog.logger.class%" public="false">
-            <argument>framework</argument>
+        <service id="monolog.logger" parent="monolog.logger_prototype">
+            <argument index="0">app</argument>
+        </service>
+        <service id="monolog.logger_prototype" class="%monolog.logger.class%" abstract="true">
+            <argument /><!-- Channel -->
         </service>
     </services>
 </container>

+ 54 - 0
src/Symfony/Bundle/MonologBundle/Tests/DependencyInjection/Compiler/LoggerChannelPassTest.php

@@ -0,0 +1,54 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\MonologBundle\Tests\DependencyInjection\Compiler;
+
+use Symfony\Bundle\MonologBundle\Tests\TestCase;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Bundle\MonologBundle\DependencyInjection\Compiler\LoggerChannelPass;
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
+
+class LoggerChannelPassTest extends TestCase
+{
+    public function testProcess()
+    {
+        $container = $this->getContainer();
+        $this->assertTrue($container->hasDefinition('monolog.logger.test'), '->process adds a logger service for tagged service');
+
+        $service = $container->getDefinition('test');
+        $arguments = $service->getArguments();
+        $this->assertEquals('monolog.logger.test', (string) $arguments[1], '->process replaces the logger by the new one');
+    }
+
+    protected function getContainer()
+    {
+        $container = new ContainerBuilder();
+        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../../../Resources/config'));
+        $loader->load('monolog.xml');
+        $definition = $container->getDefinition('monolog.logger_prototype');
+        $container->set('monolog.handler.test', new Definition('%monolog.handler.null.class%', array (100, false)));
+        $definition->addMethodCall('pushHandler', array(new Reference('monolog.handler.test')));
+
+        $service = new Definition('TestClass', array('false', new Reference('logger')));
+        $service->addTag('monolog.logger', array ('channel' => 'test'));
+        $container->setDefinition('test', $service);
+
+        $container->getCompilerPassConfig()->setOptimizationPasses(array());
+        $container->getCompilerPassConfig()->setRemovingPasses(array());
+        $container->addCompilerPass(new LoggerChannelPass());
+        $container->compile();
+
+        return $container;
+    }
+}