diff --git a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php index 22a4faac5cc9a..dbd8f3fb31b97 100644 --- a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php @@ -16,11 +16,27 @@ class DebugProcessor implements DebugLoggerInterface { + private $channels = array(); + private $channelsExclusive = true; private $records = array(); private $errorCount = 0; + /** + * @param array $channels + * @param bool $exclude + */ + public function setFilterChannels(array $channels, $exclude = true) + { + $this->channels = $channels; + $this->channelsExclusive = (bool) $exclude; + } + public function __invoke(array $record) { + if ($this->isFiltered($record)) { + return $record; + } + $this->records[] = array( 'timestamp' => $record['datetime']->getTimestamp(), 'message' => $record['message'], @@ -40,6 +56,17 @@ public function __invoke(array $record) return $record; } + private function isFiltered(array $record) + { + if ($this->channelsExclusive && !in_array($record['channel'], $this->channels)) { + return false; + } elseif (!$this->channelsExclusive && in_array($record['channel'], $this->channels)) { + return false; + } + + return true; + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php new file mode 100644 index 0000000000000..c0cce6727f516 --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Tests\Processor; + +use Monolog\Handler\TestHandler; +use Monolog\Logger; +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\Monolog\Processor\DebugProcessor; + +class DebugProcessorTest extends TestCase +{ + public function testNoChannelsAreFilteredByDefault() + { + $handler = new TestHandler(); + $processor = new DebugProcessor(); + + $aLogger = new Logger('a', array($handler), array($processor)); + $bLogger = new Logger('b', array($handler), array($processor)); + + $aLogger->info('test A'); + $bLogger->info('test B'); + + $logs = $processor->getLogs(); + $this->assertCount(2, $logs); + + $this->assertEquals('a', $logs[0]['channel']); + $this->assertEquals('test A', $logs[0]['message']); + + $this->assertEquals('b', $logs[1]['channel']); + $this->assertEquals('test B', $logs[1]['message']); + } + + public function testExcludedChannels() + { + $handler = new TestHandler(); + + $processor = new DebugProcessor(); + $processor->setFilterChannels(array('a'), true); + + $aLogger = new Logger('a', array($handler), array($processor)); + $bLogger = new Logger('b', array($handler), array($processor)); + + $aLogger->info('test A'); + $bLogger->info('test B'); + + $logs = $processor->getLogs(); + $this->assertCount(1, $logs); + + $this->assertEquals('b', $logs[0]['channel']); + $this->assertEquals('test B', $logs[0]['message']); + } + + public function testIncludedChannels() + { + $handler = new TestHandler(); + + $processor = new DebugProcessor(); + $processor->setFilterChannels(array('a'), false); + + $aLogger = new Logger('a', array($handler), array($processor)); + $bLogger = new Logger('b', array($handler), array($processor)); + + $aLogger->info('test A'); + $bLogger->info('test B'); + + $logs = $processor->getLogs(); + $this->assertCount(1, $logs); + + $this->assertEquals('a', $logs[0]['channel']); + $this->assertEquals('test A', $logs[0]['message']); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index c089a8b40a743..de4d479909722 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -10,6 +10,7 @@ CHANGELOG require symfony/stopwatch` in your `dev` environment. * Deprecated using the `KERNEL_DIR` environment variable with `KernelTestCase::getKernelClass()`. * Deprecated the `KernelTestCase::getPhpUnitXmlDir()` and `KernelTestCase::getPhpUnitCliConfigArgument()` methods. + * Added a configuration to exclude logging channels from the profiler by setting `framework.profiler.log_channels`. 3.3.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 3f9c4eee02421..3d19fa9e1adcd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -17,6 +17,7 @@ use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; +use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\Form\Form; use Symfony\Component\Serializer\Serializer; use Symfony\Component\Translation\Translator; @@ -219,6 +220,64 @@ private function addProfilerSection(ArrayNodeDefinition $rootNode) ->booleanNode('only_exceptions')->defaultFalse()->end() ->booleanNode('only_master_requests')->defaultFalse()->end() ->scalarNode('dsn')->defaultValue('file:%kernel.cache_dir%/profiler')->end() + ->arrayNode('log_channels') + ->info('list of log channels to handle in profiler') + ->canBeUnset() + ->beforeNormalization() + ->ifString() + ->then(function ($v) { return array('channels' => array($v)); }) + ->end() + ->beforeNormalization() + ->ifTrue(function ($v) { return is_array($v) && is_numeric(key($v)); }) + ->then(function ($v) { return array('channels' => $v); }) + ->end() + ->validate() + ->ifTrue(function ($v) { return empty($v); }) + ->thenUnset() + ->end() + ->validate() + ->always(function ($v) { + $isExclusive = null; + if (isset($v['type'])) { + $isExclusive = 'exclusive' === $v['type']; + } + + $channels = array(); + foreach ($v['channels'] as $channel) { + if (0 === strpos($channel, '!')) { + if (false === $isExclusive) { + throw new InvalidConfigurationException('Cannot combine exclusive/inclusive definitions in profiler log_channels list.'); + } + $channels[] = substr($channel, 1); + $isExclusive = true; + } else { + if (true === $isExclusive) { + throw new InvalidConfigurationException('Cannot combine exclusive/inclusive definitions in profiler log_channels list'); + } + $channels[] = $channel; + $isExclusive = false; + } + } + + if (!count($channels)) { + return null; + } + + return array('type' => $isExclusive ? 'exclusive' : 'inclusive', 'channels' => $channels); + }) + ->end() + ->children() + ->scalarNode('type') + ->validate() + ->ifNotInArray(array('inclusive', 'exclusive')) + ->thenInvalid('The type of log_channels has to be inclusive or exclusive') + ->end() + ->end() + ->arrayNode('channels') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() ->arrayNode('matcher') ->canBeEnabled() ->performNoDeepMerging() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 1769258215475..431885b5252a1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -231,6 +231,7 @@ public function load(array $configs, ContainerBuilder $container) $this->registerCacheConfiguration($config['cache'], $container); $this->registerWorkflowConfiguration($config['workflows'], $container, $loader); $this->registerDebugConfiguration($config['php_errors'], $container, $loader); + $this->registerDebugLoggerConfiguration($config['profiler'], $container); if ($this->isConfigEnabled($container, $config['router'])) { $this->registerRouterConfiguration($config['router'], $container, $loader); @@ -672,10 +673,29 @@ private function registerDebugConfiguration(array $config, ContainerBuilder $con $definition->replaceArgument(4, $debug); $definition->replaceArgument(6, $debug); + } + + /** + * Registers the debug log processor if debug is enabled. + * + * @param array $config + * @param ContainerBuilder $container + */ + private function registerDebugLoggerConfiguration(array $config, ContainerBuilder $container) + { + $debug = $container->getParameter('kernel.debug'); if ($debug && class_exists(DebugProcessor::class)) { $definition = new Definition(DebugProcessor::class); $definition->setPublic(false); + + if (isset($config['log_channels'])) { + $definition->addMethodCall('setChannels', array( + $config['log_channels']['channels'], + $config['log_channels']['type'] === 'exclusive', + )); + } + $container->setDefinition('debug.log_processor', $definition); } }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: