Skip to content

Commit

Permalink
Add handler_default_channels configuration option
Browse files Browse the repository at this point in the history
  • Loading branch information
HypeMC committed Mar 21, 2023
1 parent 0e136c5 commit 81c547c
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 22 deletions.
45 changes: 24 additions & 21 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,8 @@ public function getConfigTreeBuilder()
$treeBuilder = new TreeBuilder('monolog');
$rootNode = method_exists(TreeBuilder::class, 'getRootNode') ? $treeBuilder->getRootNode() : $treeBuilder->root('monolog');

$this->addChannelsSection($rootNode, 'handler_default_channels');

$handlers = $rootNode
->fixXmlConfig('channel')
->fixXmlConfig('handler')
Expand Down Expand Up @@ -621,6 +623,7 @@ public function getConfigTreeBuilder()
->end()
->scalarNode('formatter')->end()
->booleanNode('nested')->defaultFalse()->end()
->booleanNode('use_default_channels')->defaultTrue()->end()
->end();

$this->addGelfSection($handlerNode);
Expand Down Expand Up @@ -793,9 +796,9 @@ public function getConfigTreeBuilder()
return $treeBuilder;
}

private function addGelfSection(ArrayNodeDefinition $handerNode)
private function addGelfSection(ArrayNodeDefinition $handlerNode)
{
$handerNode
$handlerNode
->children()
->arrayNode('publisher')
->canBeUnset()
Expand Down Expand Up @@ -824,9 +827,9 @@ private function addGelfSection(ArrayNodeDefinition $handerNode)
;
}

private function addMongoSection(ArrayNodeDefinition $handerNode)
private function addMongoSection(ArrayNodeDefinition $handlerNode)
{
$handerNode
$handlerNode
->children()
->arrayNode('mongo')
->canBeUnset()
Expand Down Expand Up @@ -864,9 +867,9 @@ private function addMongoSection(ArrayNodeDefinition $handerNode)
;
}

private function addElasticsearchSection(ArrayNodeDefinition $handerNode)
private function addElasticsearchSection(ArrayNodeDefinition $handlerNode)
{
$handerNode
$handlerNode
->children()
->arrayNode('elasticsearch')
->canBeUnset()
Expand Down Expand Up @@ -896,9 +899,9 @@ private function addElasticsearchSection(ArrayNodeDefinition $handerNode)
;
}

private function addRedisSection(ArrayNodeDefinition $handerNode)
private function addRedisSection(ArrayNodeDefinition $handlerNode)
{
$handerNode
$handlerNode
->children()
->arrayNode('redis')
->canBeUnset()
Expand Down Expand Up @@ -929,9 +932,9 @@ private function addRedisSection(ArrayNodeDefinition $handerNode)
;
}

private function addPredisSection(ArrayNodeDefinition $handerNode)
private function addPredisSection(ArrayNodeDefinition $handlerNode)
{
$handerNode
$handlerNode
->children()
->arrayNode('predis')
->canBeUnset()
Expand All @@ -958,9 +961,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
Expand Down Expand Up @@ -1005,9 +1008,9 @@ private function addMailerSection(ArrayNodeDefinition $handerNode)
;
}

private function addVerbosityLevelSection(ArrayNodeDefinition $handerNode)
private function addVerbosityLevelSection(ArrayNodeDefinition $handlerNode)
{
$handerNode
$handlerNode
->children()
->arrayNode('verbosity_levels') // console
->beforeNormalization()
Expand Down Expand Up @@ -1071,11 +1074,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()
Expand All @@ -1091,7 +1094,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'];
Expand All @@ -1101,13 +1104,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;
Expand All @@ -1126,7 +1129,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')
Expand Down
12 changes: 11 additions & 1 deletion DependencyInjection/MonologExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,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'],
];
}

Expand All @@ -90,10 +91,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);
Expand Down
2 changes: 2 additions & 0 deletions Resources/config/schema/monolog-1.0.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="handler" type="handler" />
<xsd:element name="channel" type="xsd:string" />
<xsd:element name="handler-default-channels" type="channels" minOccurs="0" maxOccurs="1" />
</xsd:choice>
</xsd:complexType>

Expand Down Expand Up @@ -92,6 +93,7 @@
<xsd:attribute name="webhook-url" type="xsd:string" />
<xsd:attribute name="slack-team" type="xsd:string" />
<xsd:attribute name="region" type="xsd:string" />
<xsd:attribute name="use-default-channels" type="xsd:boolean" />
</xsd:complexType>

<xsd:simpleType name="level">
Expand Down
47 changes: 47 additions & 0 deletions Tests/DependencyInjection/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down Expand Up @@ -549,6 +574,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.
*
Expand Down
55 changes: 55 additions & 0 deletions Tests/DependencyInjection/FixtureMonologExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,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()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:monolog="http://symfony.com/schema/dic/monolog"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">

<monolog:config>
<monolog:channel>foo</monolog:channel>
<monolog:channel>bar</monolog:channel>
<monolog:channel>baz</monolog:channel>

<monolog:handler-default-channels>
<monolog:channel>!foo</monolog:channel>
<monolog:channel>!bar</monolog:channel>
</monolog:handler-default-channels>

<monolog:handler name="one" type="stream" use-default-channels="true">
<monolog:channels>
<monolog:channel>foo</monolog:channel>
</monolog:channels>
</monolog:handler>
<monolog:handler name="two" type="stream" use-default-channels="false">
<monolog:channels>
<monolog:channel>!bar</monolog:channel>
<monolog:channel>!baz</monolog:channel>
</monolog:channels>
</monolog:handler>
<monolog:handler name="three" type="stream" use-default-channels="true">
<monolog:channels>
<monolog:channel>!bar</monolog:channel>
<monolog:channel>!baz</monolog:channel>
</monolog:channels>
</monolog:handler>
<monolog:handler name="four" type="stream" use-default-channels="true" />
<monolog:handler name="five" type="stream" use-default-channels="false" />
<monolog:handler name="six" type="stream" />
</monolog:config>
</container>
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 81c547c

Please sign in to comment.