Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add handler_default_channels configuration option #454

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 24 additions & 21 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand All @@ -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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand All @@ -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'];
Expand All @@ -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;
Expand All @@ -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')
Expand Down
12 changes: 11 additions & 1 deletion DependencyInjection/MonologExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
];
}

Expand All @@ -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);
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 @@ -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.
*
Expand Down
55 changes: 55 additions & 0 deletions Tests/DependencyInjection/FixtureMonologExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
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
Loading