Преглед изворни кода

[MonologBundle] Added the MonologBundle

Jordi Boggiano пре 14 година
родитељ
комит
6114cccf7f

+ 64 - 0
src/Symfony/Bundle/MonologBundle/DependencyInjection/Configuration.php

@@ -0,0 +1,64 @@
+<?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;
+
+use Symfony\Component\Config\Definition\Builder\NodeBuilder;
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+
+/**
+ * This class contains the configuration information for the bundle
+ *
+ * This information is solely responsible for how the different configuration
+ * sections are normalized, and merged.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class Configuration
+{
+    /**
+     * Generates the configuration tree.
+     *
+     * @return \Symfony\Component\Config\Definition\NodeInterface
+     */
+    public function getConfigTree()
+    {
+        $treeBuilder = new TreeBuilder();
+        $rootNode = $treeBuilder->root('monolog', 'array');
+
+        // TODO update XSD to match this
+        $rootNode
+            ->arrayNode('handlers')
+                ->fixXmlConfig('handler')
+                ->canBeUnset()
+                ->performNoDeepMerging()
+                ->prototype('array')
+                    ->performNoDeepMerging()
+                    // TODO lowercase the type always
+                    ->scalarNode('type')->isRequired()->end()
+                    ->scalarNode('action_level')->end()
+                    ->scalarNode('level')->defaultValue('INFO')->end()
+                    ->scalarNode('path')->end()
+                    ->scalarNode('bubble')->end()
+                    ->scalarNode('buffer_size')->end()
+                    ->arrayNode('handler')
+                        ->performNoDeepMerging()
+                        ->scalarNode('type')->isRequired()->end()
+                        ->scalarNode('level')->defaultValue('DEBUG')->end()
+                        ->scalarNode('path')->end()
+                    ->end()
+                ->end()
+            ->end()
+        ;
+
+        return $treeBuilder->buildTree();
+    }
+}

+ 125 - 0
src/Symfony/Bundle/MonologBundle/DependencyInjection/MonologExtension.php

@@ -0,0 +1,125 @@
+<?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;
+
+use Symfony\Component\HttpKernel\DependencyInjection\Extension;
+use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\Config\Definition\Processor;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\Parameter;
+
+/**
+ * MonologExtension is an extension for the Monolog library.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class MonologExtension extends Extension
+{
+    /**
+     * Loads the Monolog configuration.
+     *
+     * Usage example:
+     *
+     *      monolog:
+     *          handlers:
+     *              myhandler:
+     *                  level: info
+     *                  path: path/to/some.log
+     *
+     * @param array            $config    An array of configuration settings
+     * @param ContainerBuilder $container A ContainerBuilder instance
+     */
+    public function load(array $configs, ContainerBuilder $container)
+    {
+        $configuration = new Configuration();
+        $processor = new Processor();
+        $config = $processor->process($configuration->getConfigTree(), $configs);
+
+        if (isset($config['handlers'])) {
+            $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
+            $loader->load('monolog.xml');
+            $container->setAlias('logger', 'monolog.logger');
+
+            $logger = $container->getDefinition('monolog.logger');
+
+            $handlers = array();
+            foreach ($config['handlers'] as $handler) {
+                $handlers[] = $this->buildHandler($container, $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));
+            }
+        }
+    }
+
+    public function buildHandler(ContainerBuilder $container, array $handler)
+    {
+        $definition = new Definition(new Parameter('monolog.handler.'.$handler['type'].'.class'));
+        $handler['level'] = is_int($handler['level']) ? $handler['level'] : constant('Monolog\Logger::'.strtoupper($handler['level']));
+
+        switch ($handler['type']) {
+        case 'stream':
+            if (!isset($handler['path'])) {
+                $handler['path'] = '%kernel.logs_dir%/%kernel.environment%.log';
+            }
+
+            $definition->setArguments(array(
+                $handler['path'],
+                $handler['level'],
+                isset($handler['bubble']) ? $handler['bubble'] : false,
+            ));
+            break;
+
+        case 'fingerscrossed':
+            if (!isset($handler['handler'])) {
+                // TODO validate that in Config class?
+                throw new \InvalidArgumentException('Handler sub-node is missing.');
+            }
+            if (!isset($handler['action_level'])) {
+                $handler['action_level'] = 'WARNING';
+            }
+            $handler['action_level'] = is_int($handler['action_level']) ? $handler['action_level'] : constant('Monolog\Logger::'.strtoupper($handler['action_level']));
+
+            $definition->setArguments(array(
+                $this->buildHandler($container, $handler['handler']),
+                $handler['action_level'],
+                isset($handler['buffer_size']) ? $handler['buffer_size'] : 0,
+                isset($handler['bubble']) ? $handler['bubble'] : false,
+            ));
+            break;
+        }
+
+        return $definition;
+    }
+
+    /**
+     * Returns the base path for the XSD files.
+     *
+     * @return string The XSD base path
+     */
+    public function getXsdValidationBasePath()
+    {
+        return __DIR__.'/../Resources/config/schema';
+    }
+
+    public function getNamespace()
+    {
+        return 'http://www.symfony-project.org/schema/dic/monolog';
+    }
+}

+ 40 - 0
src/Symfony/Bundle/MonologBundle/Logger/DebugLogger.php

@@ -0,0 +1,40 @@
+<?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\Logger;
+
+use Monolog\Handler\TestHandler;
+use Monolog\Logger;
+use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
+
+/**
+ * DebugLogger.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class DebugLogger extends TestHandler implements DebugLoggerInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getLogs()
+    {
+        return $this->messages;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function countErrors()
+    {
+        return count($this->messagesByLevel[Logger::ERROR]);
+    }
+}

+ 47 - 0
src/Symfony/Bundle/MonologBundle/Logger/Logger.php

@@ -0,0 +1,47 @@
+<?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\Logger;
+
+use Monolog\Logger as BaseLogger;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
+
+/**
+ * Logger.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class Logger extends BaseLogger implements LoggerInterface
+{
+    /**
+     * Returns a DebugLoggerInterface instance if one is registered with this logger.
+     *
+     * @return DebugLoggerInterface A DebugLoggerInterface instance or null if none is registered
+     */
+    public function getDebugLogger()
+    {
+        $handler = $this->handler;
+        while ($handler) {
+            if ($handler instanceof DebugLoggerInterface) {
+                return $handler;
+            }
+            $handler = $handler->getParent();
+        }
+
+        return null;
+    }
+
+    public function log($message, $level)
+    {
+        return $this->addMessage($level, $message);
+    }
+}

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

@@ -0,0 +1,23 @@
+<?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;
+
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+/**
+ * Bundle.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class MonologBundle extends Bundle
+{
+}

+ 18 - 0
src/Symfony/Bundle/MonologBundle/Resources/config/monolog.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" ?>
+
+<container xmlns="http://www.symfony-project.org/schema/dic/services"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd">
+
+    <parameters>
+        <parameter key="monolog.logger.class">Symfony\Bundle\MonologBundle\Logger\Logger</parameter>
+        <parameter key="monolog.handler.stream.class">Monolog\Handler\StreamHandler</parameter>
+        <parameter key="monolog.handler.fingerscrossed.class">Monolog\Handler\FingersCrossedHandler</parameter>
+    </parameters>
+
+    <services>
+        <service id="monolog.logger" class="%monolog.logger.class%" public="false">
+            <argument>framework</argument>
+        </service>
+    </services>
+</container>

+ 34 - 0
src/Symfony/Bundle/MonologBundle/Resources/config/schema/monolog-1.0.xsd

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<xsd:schema xmlns="http://www.symfony-project.org/schema/dic/monolog"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    targetNamespace="http://www.symfony-project.org/schema/dic/monolog"
+    elementFormDefault="qualified">
+
+    <xsd:element name="config" type="config" />
+
+    <xsd:complexType name="config">
+        <xsd:all>
+            <xsd:element name="handler" type="handler" minOccurs="0" maxOccurs="unbounded" />
+        </xsd:all>
+    </xsd:complexType>
+
+    <xsd:complexType name="handler">
+        <xsd:attribute name="level" type="level" />
+        <xsd:attribute name="path" type="xsd:string" />
+    </xsd:complexType>
+
+    <xsd:simpleType name="level">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="error" />
+            <xsd:enumeration value="warning" />
+            <xsd:enumeration value="info" />
+            <xsd:enumeration value="debug" />
+
+            <xsd:enumeration value="100" />
+            <xsd:enumeration value="200" />
+            <xsd:enumeration value="300" />
+            <xsd:enumeration value="400" />
+        </xsd:restriction>
+    </xsd:simpleType>
+</xsd:schema>

+ 22 - 0
src/Symfony/Bundle/MonologBundle/Tests/TestCase.php

@@ -0,0 +1,22 @@
+<?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;
+
+class TestCase extends \PHPUnit_Framework_TestCase
+{
+    protected function setUp()
+    {
+        if (!class_exists('Monolog\Logger')) {
+            $this->markTestSkipped('Monolog is not available.');
+        }
+    }
+}