From 7572a53b847af0c74ec1c23cd56087c46f9a2978 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 4 Nov 2016 21:47:40 +0100 Subject: [PATCH] [Bridge\Monolog][FrameworkBundle] Add & wire a DebugProcessor --- .../Bridge/Monolog/Handler/DebugHandler.php | 4 ++ src/Symfony/Bridge/Monolog/Logger.php | 6 ++ .../Monolog/Processor/DebugProcessor.php | 58 ++++++++++++++++++ .../Bridge/Monolog/Tests/LoggerTest.php | 59 ++++++++++++++++++- .../Compiler/AddDebugLogProcessorPass.php | 35 +++++++++++ .../FrameworkExtension.php | 7 +++ .../FrameworkBundle/FrameworkBundle.php | 2 + 7 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php diff --git a/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php b/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php index f1046c96a6..6032750ff6 100644 --- a/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php @@ -11,6 +11,8 @@ namespace Symfony\Bridge\Monolog\Handler; +@trigger_error('The '.__NAMESPACE__.'\DebugHandler class is deprecated since version 3.2 and will be removed in 4.0. Use Symfony\Bridge\Monolog\Processor\DebugProcessor instead.', E_USER_DEPRECATED); + use Monolog\Logger; use Monolog\Handler\TestHandler; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; @@ -19,6 +21,8 @@ use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; * DebugLogger. * * @author Jordi Boggiano + * + * @deprecated since version 3.2, to be removed in 4.0. Use Symfony\Bridge\Monolog\Processor\DebugProcessor instead. */ class DebugHandler extends TestHandler implements DebugLoggerInterface { diff --git a/src/Symfony/Bridge/Monolog/Logger.php b/src/Symfony/Bridge/Monolog/Logger.php index f0e108081b..ec6434fe79 100644 --- a/src/Symfony/Bridge/Monolog/Logger.php +++ b/src/Symfony/Bridge/Monolog/Logger.php @@ -52,6 +52,12 @@ class Logger extends BaseLogger implements DebugLoggerInterface */ private function getDebugLogger() { + foreach ($this->processors as $processor) { + if ($processor instanceof DebugLoggerInterface) { + return $processor; + } + } + foreach ($this->handlers as $handler) { if ($handler instanceof DebugLoggerInterface) { return $handler; diff --git a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php new file mode 100644 index 0000000000..22a4faac5c --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Processor; + +use Monolog\Logger; +use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; + +class DebugProcessor implements DebugLoggerInterface +{ + private $records = array(); + private $errorCount = 0; + + public function __invoke(array $record) + { + $this->records[] = array( + 'timestamp' => $record['datetime']->getTimestamp(), + 'message' => $record['message'], + 'priority' => $record['level'], + 'priorityName' => $record['level_name'], + 'context' => $record['context'], + 'channel' => isset($record['channel']) ? $record['channel'] : '', + ); + switch ($record['level']) { + case Logger::ERROR: + case Logger::CRITICAL: + case Logger::ALERT: + case Logger::EMERGENCY: + ++$this->errorCount; + } + + return $record; + } + + /** + * {@inheritdoc} + */ + public function getLogs() + { + return $this->records; + } + + /** + * {@inheritdoc} + */ + public function countErrors() + { + return $this->errorCount; + } +} diff --git a/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php b/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php index e685ef041f..9597d01c96 100644 --- a/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php @@ -13,10 +13,14 @@ namespace Symfony\Bridge\Monolog\Tests; use Monolog\Handler\TestHandler; use Symfony\Bridge\Monolog\Handler\DebugHandler; +use Symfony\Bridge\Monolog\Processor\DebugProcessor; use Symfony\Bridge\Monolog\Logger; class LoggerTest extends \PHPUnit_Framework_TestCase { + /** + * @group legacy + */ public function testGetLogsWithDebugHandler() { $handler = new DebugHandler(); @@ -26,7 +30,7 @@ class LoggerTest extends \PHPUnit_Framework_TestCase $this->assertSame(1, count($logger->getLogs())); } - public function testGetLogsWithoutDebugHandler() + public function testGetLogsWithoutDebugProcessor() { $handler = new TestHandler(); $logger = new Logger(__METHOD__, array($handler)); @@ -35,6 +39,9 @@ class LoggerTest extends \PHPUnit_Framework_TestCase $this->assertSame(array(), $logger->getLogs()); } + /** + * @group legacy + */ public function testCountErrorsWithDebugHandler() { $handler = new DebugHandler(); @@ -53,7 +60,10 @@ class LoggerTest extends \PHPUnit_Framework_TestCase $this->assertSame(4, $logger->countErrors()); } - public function testGetLogs() + /** + * @group legacy + */ + public function testGetLogsWithDebugHandler2() { $logger = new Logger('test'); $logger->pushHandler(new DebugHandler()); @@ -66,7 +76,7 @@ class LoggerTest extends \PHPUnit_Framework_TestCase $this->assertEquals(Logger::INFO, $record['priority']); } - public function testCountErrorsWithoutDebugHandler() + public function testCountErrorsWithoutDebugProcessor() { $handler = new TestHandler(); $logger = new Logger(__METHOD__, array($handler)); @@ -74,4 +84,47 @@ class LoggerTest extends \PHPUnit_Framework_TestCase $this->assertTrue($logger->error('error message')); $this->assertSame(0, $logger->countErrors()); } + + public function testGetLogsWithDebugProcessor() + { + $handler = new TestHandler(); + $processor = new DebugProcessor(); + $logger = new Logger(__METHOD__, array($handler), array($processor)); + + $this->assertTrue($logger->error('error message')); + $this->assertSame(1, count($logger->getLogs())); + } + + public function testCountErrorsWithDebugProcessor() + { + $handler = new TestHandler(); + $processor = new DebugProcessor(); + $logger = new Logger(__METHOD__, array($handler), array($processor)); + + $this->assertTrue($logger->debug('test message')); + $this->assertTrue($logger->info('test message')); + $this->assertTrue($logger->notice('test message')); + $this->assertTrue($logger->warning('test message')); + + $this->assertTrue($logger->error('test message')); + $this->assertTrue($logger->critical('test message')); + $this->assertTrue($logger->alert('test message')); + $this->assertTrue($logger->emergency('test message')); + + $this->assertSame(4, $logger->countErrors()); + } + + public function testGetLogsWithDebugProcessor2() + { + $handler = new TestHandler(); + $logger = new Logger('test', array($handler)); + $logger->pushProcessor(new DebugProcessor()); + + $logger->addInfo('test'); + $this->assertCount(1, $logger->getLogs()); + list($record) = $logger->getLogs(); + + $this->assertEquals('test', $record['message']); + $this->assertEquals(Logger::INFO, $record['priority']); + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php new file mode 100644 index 0000000000..4d8e5175c6 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\Reference; + +class AddDebugLogProcessorPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('profiler')) { + return; + } + if (!$container->hasDefinition('monolog.logger_prototype')) { + return; + } + if (!$container->hasDefinition('debug.log_processor')) { + return; + } + + $definition = $container->getDefinition('monolog.logger_prototype'); + $definition->addMethodCall('pushProcessor', array(new Reference('debug.log_processor'))); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index c3eab37c9c..1ea7441fad 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\FrameworkBundle\DependencyInjection; use Doctrine\Common\Annotations\Reader; +use Symfony\Bridge\Monolog\Processor\DebugProcessor; use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -468,6 +469,12 @@ class FrameworkExtension extends Extension $definition->replaceArgument(4, $debug); $definition->replaceArgument(6, $debug); + + if ($debug && class_exists(DebugProcessor::class)) { + $definition = new Definition(DebugProcessor::class); + $definition->setPublic(false); + $container->setDefinition('debug.log_processor', $definition); + } } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 7148f56046..a736c091a1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\FrameworkBundle; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddDebugLogProcessorPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolPass; @@ -95,6 +96,7 @@ class FrameworkBundle extends Bundle $container->addCompilerPass(new CachePoolClearerPass(), PassConfig::TYPE_AFTER_REMOVING); if ($container->getParameter('kernel.debug')) { + $container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -1); $container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new CompilerDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING);