diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php
index 255eba47..cad71230 100644
--- a/DependencyInjection/Configuration.php
+++ b/DependencyInjection/Configuration.php
@@ -386,6 +386,8 @@ public function getConfigTreeBuilder(): TreeBuilder
$treeBuilder = new TreeBuilder('monolog');
$rootNode = $treeBuilder->getRootNode();
+ $this->addChannelsSection($rootNode, 'handler_default_channels');
+
$handlers = $rootNode
->fixXmlConfig('channel')
->fixXmlConfig('handler')
@@ -625,6 +627,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->scalarNode('formatter')->end()
->booleanNode('nested')->defaultFalse()->end()
+ ->booleanNode('use_default_channels')->defaultTrue()->end()
->end();
$this->addGelfSection($handlerNode);
@@ -801,9 +804,9 @@ public function getConfigTreeBuilder(): TreeBuilder
return $treeBuilder;
}
- private function addGelfSection(ArrayNodeDefinition $handerNode)
+ private function addGelfSection(ArrayNodeDefinition $handlerNode)
{
- $handerNode
+ $handlerNode
->children()
->arrayNode('publisher')
->canBeUnset()
@@ -832,9 +835,9 @@ private function addGelfSection(ArrayNodeDefinition $handerNode)
;
}
- private function addMongoSection(ArrayNodeDefinition $handerNode)
+ private function addMongoSection(ArrayNodeDefinition $handlerNode)
{
- $handerNode
+ $handlerNode
->children()
->arrayNode('mongo')
->canBeUnset()
@@ -872,9 +875,9 @@ private function addMongoSection(ArrayNodeDefinition $handerNode)
;
}
- private function addElasticsearchSection(ArrayNodeDefinition $handerNode)
+ private function addElasticsearchSection(ArrayNodeDefinition $handlerNode)
{
- $handerNode
+ $handlerNode
->children()
->arrayNode('elasticsearch')
->canBeUnset()
@@ -904,9 +907,9 @@ private function addElasticsearchSection(ArrayNodeDefinition $handerNode)
;
}
- private function addRedisSection(ArrayNodeDefinition $handerNode)
+ private function addRedisSection(ArrayNodeDefinition $handlerNode)
{
- $handerNode
+ $handlerNode
->children()
->arrayNode('redis')
->canBeUnset()
@@ -937,9 +940,9 @@ private function addRedisSection(ArrayNodeDefinition $handerNode)
;
}
- private function addPredisSection(ArrayNodeDefinition $handerNode)
+ private function addPredisSection(ArrayNodeDefinition $handlerNode)
{
- $handerNode
+ $handlerNode
->children()
->arrayNode('predis')
->canBeUnset()
@@ -966,9 +969,9 @@ private function addPredisSection(ArrayNodeDefinition $handerNode)
;
}
- private function addMailerSection(ArrayNodeDefinition $handerNode)
+ private function addMailerSection(ArrayNodeDefinition $handlerNode)
{
- $handerNode
+ $handlerNode
->children()
->scalarNode('from_email')->end() // swift_mailer, native_mailer, symfony_mailer and flowdock
->arrayNode('to_email') // swift_mailer, native_mailer and symfony_mailer
@@ -1013,9 +1016,9 @@ private function addMailerSection(ArrayNodeDefinition $handerNode)
;
}
- private function addVerbosityLevelSection(ArrayNodeDefinition $handerNode)
+ private function addVerbosityLevelSection(ArrayNodeDefinition $handlerNode)
{
- $handerNode
+ $handlerNode
->children()
->arrayNode('verbosity_levels') // console
->beforeNormalization()
@@ -1073,11 +1076,11 @@ private function addVerbosityLevelSection(ArrayNodeDefinition $handerNode)
;
}
- private function addChannelsSection(ArrayNodeDefinition $handerNode)
+ private function addChannelsSection(ArrayNodeDefinition $handlerNode, string $nodeName = 'channels')
{
- $handerNode
+ $handlerNode
->children()
- ->arrayNode('channels')
+ ->arrayNode($nodeName)
->fixXmlConfig('channel', 'elements')
->canBeUnset()
->beforeNormalization()
@@ -1093,7 +1096,7 @@ private function addChannelsSection(ArrayNodeDefinition $handerNode)
->thenUnset()
->end()
->validate()
- ->always(function ($v) {
+ ->always(function ($v) use ($nodeName) {
$isExclusive = null;
if (isset($v['type'])) {
$isExclusive = 'exclusive' === $v['type'];
@@ -1103,13 +1106,13 @@ private function addChannelsSection(ArrayNodeDefinition $handerNode)
foreach ($v['elements'] as $element) {
if (0 === strpos($element, '!')) {
if (false === $isExclusive) {
- throw new InvalidConfigurationException('Cannot combine exclusive/inclusive definitions in channels list.');
+ throw new InvalidConfigurationException(\sprintf('Cannot combine exclusive/inclusive definitions in %s list.', $nodeName));
}
$elements[] = substr($element, 1);
$isExclusive = true;
} else {
if (true === $isExclusive) {
- throw new InvalidConfigurationException('Cannot combine exclusive/inclusive definitions in channels list');
+ throw new InvalidConfigurationException(\sprintf('Cannot combine exclusive/inclusive definitions in %s list', $nodeName));
}
$elements[] = $element;
$isExclusive = false;
@@ -1128,7 +1131,7 @@ private function addChannelsSection(ArrayNodeDefinition $handerNode)
->scalarNode('type')
->validate()
->ifNotInArray(['inclusive', 'exclusive'])
- ->thenInvalid('The type of channels has to be inclusive or exclusive')
+ ->thenInvalid(\sprintf('The type of %s has to be inclusive or exclusive', $nodeName))
->end()
->end()
->arrayNode('elements')
diff --git a/DependencyInjection/MonologExtension.php b/DependencyInjection/MonologExtension.php
index 1d47a984..df12b645 100644
--- a/DependencyInjection/MonologExtension.php
+++ b/DependencyInjection/MonologExtension.php
@@ -76,6 +76,7 @@ public function load(array $configs, ContainerBuilder $container)
$handlers[$handler['priority']][] = [
'id' => $this->buildHandler($container, $name, $handler),
'channels' => empty($handler['channels']) ? null : $handler['channels'],
+ 'use_default_channels' => $handler['use_default_channels'],
];
}
@@ -92,10 +93,19 @@ public function load(array $configs, ContainerBuilder $container)
}
}
+ $defaultChannels = $config['handler_default_channels'] ?? null;
$handlersToChannels = [];
foreach ($sortedHandlers as $handler) {
if (!\in_array($handler['id'], $this->nestedHandlers)) {
- $handlersToChannels[$handler['id']] = $handler['channels'];
+ $channels = $handler['channels'];
+ if (null !== $defaultChannels && $handler['use_default_channels']) {
+ if (null === $channels) {
+ $channels = $defaultChannels;
+ } elseif ($channels['type'] === $defaultChannels['type']) {
+ $channels['elements'] = array_unique(array_merge($channels['elements'], $defaultChannels['elements']));
+ }
+ }
+ $handlersToChannels[$handler['id']] = $channels;
}
}
$container->setParameter('monolog.handlers_to_channels', $handlersToChannels);
diff --git a/Resources/config/schema/monolog-1.0.xsd b/Resources/config/schema/monolog-1.0.xsd
index b00e969e..898dbdf0 100644
--- a/Resources/config/schema/monolog-1.0.xsd
+++ b/Resources/config/schema/monolog-1.0.xsd
@@ -11,6 +11,7 @@
+
@@ -92,6 +93,7 @@
+
diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php
index 516565e0..cb0ed3eb 100644
--- a/Tests/DependencyInjection/ConfigurationTest.php
+++ b/Tests/DependencyInjection/ConfigurationTest.php
@@ -323,6 +323,31 @@ public function testWithType()
$this->assertEquals('B', $config['handlers']['foo']['channels']['elements'][1]);
}
+ public function testWithUseDefaultChannels()
+ {
+ $configs = [
+ [
+ 'handlers' => [
+ 'foo' => [
+ 'type' => 'stream',
+ 'path' => '/foo',
+ 'use_default_channels' => true,
+ ],
+ 'bar' => [
+ 'type' => 'stream',
+ 'path' => '/bar',
+ 'use_default_channels' => false,
+ ],
+ ],
+ ],
+ ];
+
+ $config = $this->process($configs);
+
+ $this->assertTrue($config['handlers']['foo']['use_default_channels']);
+ $this->assertFalse($config['handlers']['bar']['use_default_channels']);
+ }
+
public function testWithFilePermission()
{
$configs = [
@@ -548,6 +573,28 @@ public function processPsr3MessagesProvider(): iterable
];
}
+ /**
+ * @dataProvider provideHandlerDefaultChannels
+ */
+ public function testHandlerDefaultChannels($configuration, ?array $processedConfiguration)
+ {
+ $config = $this->process([['handler_default_channels' => $configuration]]);
+
+ $this->assertEquals($processedConfiguration, $config['handler_default_channels']);
+ }
+
+ public static function provideHandlerDefaultChannels(): iterable
+ {
+ yield 'None' => [null, null];
+ yield 'Empty array' => [[], null];
+ yield 'As string' => ['!foo', ['type' => 'exclusive', 'elements' => ['foo']]];
+ yield 'As array' => [['foo', 'bar'], ['type' => 'inclusive', 'elements' => ['foo', 'bar']]];
+ yield 'With elements key' => [['elements' => ['!foo', '!bar']], ['type' => 'exclusive', 'elements' => ['foo', 'bar']]];
+ yield 'With type key' => [['type' => 'exclusive', 'elements' => ['!foo']], ['type' => 'exclusive', 'elements' => ['foo']]];
+ yield 'XML' => [['channel' => ['foo', 'bar']], ['type' => 'inclusive', 'elements' => ['foo', 'bar']]];
+ yield 'XML with type' => [['type' => 'exclusive', 'channel' => ['!foo']], ['type' => 'exclusive', 'elements' => ['foo']]];
+ }
+
/**
* Processes an array of configurations and returns a compiled version.
*
diff --git a/Tests/DependencyInjection/FixtureMonologExtensionTest.php b/Tests/DependencyInjection/FixtureMonologExtensionTest.php
index dd0046f5..ced7f711 100644
--- a/Tests/DependencyInjection/FixtureMonologExtensionTest.php
+++ b/Tests/DependencyInjection/FixtureMonologExtensionTest.php
@@ -145,6 +145,61 @@ public function testHandlersWithChannels()
);
}
+ public function testHandlersWithDefaultChannels()
+ {
+ $container = $this->getContainer('handlers_with_default_channels');
+
+ $this->assertFalse($container->hasParameter('monolog.handler_default_channels'));
+
+ $this->assertEquals(
+ [
+ 'monolog.handler.one' => ['type' => 'inclusive', 'elements' => ['foo']],
+ 'monolog.handler.two' => ['type' => 'exclusive', 'elements' => ['bar', 'baz']],
+ 'monolog.handler.three' => ['type' => 'exclusive', 'elements' => ['bar', 'baz', 'foo']],
+ 'monolog.handler.four' => ['type' => 'exclusive', 'elements' => ['foo', 'bar']],
+ 'monolog.handler.five' => null,
+ 'monolog.handler.six' => ['type' => 'exclusive', 'elements' => ['foo', 'bar']],
+ ],
+ $container->getParameter('monolog.handlers_to_channels')
+ );
+
+ $this->assertTrue($container->hasDefinition('monolog.logger'));
+ $this->assertTrue($container->hasDefinition('monolog.logger.foo'));
+ $this->assertTrue($container->hasDefinition('monolog.logger.bar'));
+ $this->assertTrue($container->hasDefinition('monolog.logger.baz'));
+ $this->assertTrue($container->hasDefinition('monolog.handler.one'));
+ $this->assertTrue($container->hasDefinition('monolog.handler.two'));
+ $this->assertTrue($container->hasDefinition('monolog.handler.three'));
+ $this->assertTrue($container->hasDefinition('monolog.handler.four'));
+ $this->assertTrue($container->hasDefinition('monolog.handler.five'));
+ $this->assertTrue($container->hasDefinition('monolog.handler.six'));
+
+ $logger = $container->getDefinition('monolog.logger');
+ $this->assertCount(6, $logger->getMethodCalls());
+ $this->assertDICDefinitionMethodCallAt(5, $logger, 'pushHandler', [new Reference('monolog.handler.two')]);
+ $this->assertDICDefinitionMethodCallAt(4, $logger, 'pushHandler', [new Reference('monolog.handler.three')]);
+ $this->assertDICDefinitionMethodCallAt(3, $logger, 'pushHandler', [new Reference('monolog.handler.four')]);
+ $this->assertDICDefinitionMethodCallAt(2, $logger, 'pushHandler', [new Reference('monolog.handler.five')]);
+ $this->assertDICDefinitionMethodCallAt(1, $logger, 'pushHandler', [new Reference('monolog.handler.six')]);
+ $this->assertDICDefinitionMethodCallAt(0, $logger, 'useMicrosecondTimestamps', ['%monolog.use_microseconds%']);
+
+ $logger = $container->getDefinition('monolog.logger.foo');
+ $this->assertCount(3, $logger->getMethodCalls());
+ $this->assertDICDefinitionMethodCallAt(2, $logger, 'pushHandler', [new Reference('monolog.handler.one')]);
+ $this->assertDICDefinitionMethodCallAt(1, $logger, 'pushHandler', [new Reference('monolog.handler.two')]);
+ $this->assertDICDefinitionMethodCallAt(0, $logger, 'pushHandler', [new Reference('monolog.handler.five')]);
+
+ $logger = $container->getDefinition('monolog.logger.bar');
+ $this->assertCount(1, $logger->getMethodCalls());
+ $this->assertDICDefinitionMethodCallAt(0, $logger, 'pushHandler', [new Reference('monolog.handler.five')]);
+
+ $logger = $container->getDefinition('monolog.logger.baz');
+ $this->assertCount(3, $logger->getMethodCalls());
+ $this->assertDICDefinitionMethodCallAt(2, $logger, 'pushHandler', [new Reference('monolog.handler.four')]);
+ $this->assertDICDefinitionMethodCallAt(1, $logger, 'pushHandler', [new Reference('monolog.handler.five')]);
+ $this->assertDICDefinitionMethodCallAt(0, $logger, 'pushHandler', [new Reference('monolog.handler.six')]);
+ }
+
/** @group legacy */
public function testSingleEmailRecipient()
{
diff --git a/Tests/DependencyInjection/Fixtures/xml/handlers_with_default_channels.xml b/Tests/DependencyInjection/Fixtures/xml/handlers_with_default_channels.xml
new file mode 100644
index 00000000..eebd5e37
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/xml/handlers_with_default_channels.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+ foo
+ bar
+ baz
+
+
+ !foo
+ !bar
+
+
+
+
+ foo
+
+
+
+
+ !bar
+ !baz
+
+
+
+
+ !bar
+ !baz
+
+
+
+
+
+
+
diff --git a/Tests/DependencyInjection/Fixtures/yml/handlers_with_default_channels.yml b/Tests/DependencyInjection/Fixtures/yml/handlers_with_default_channels.yml
new file mode 100644
index 00000000..ff9a113e
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/yml/handlers_with_default_channels.yml
@@ -0,0 +1,24 @@
+monolog:
+ channels: [ 'foo', 'bar', 'baz' ]
+ handler_default_channels: [ '!foo', '!bar' ]
+ handlers:
+ one:
+ type: stream
+ use_default_channels: true
+ channels: foo
+ two:
+ type: stream
+ use_default_channels: false
+ channels: [ '!bar', '!baz' ]
+ three:
+ type: stream
+ use_default_channels: true
+ channels: [ '!bar', '!baz' ]
+ four:
+ type: stream
+ use_default_channels: true
+ five:
+ type: stream
+ use_default_channels: false
+ six:
+ type: stream