Skip to content

Commit

Permalink
Add ability to configure the PsrLogMessageProcessor (#417)
Browse files Browse the repository at this point in the history
  • Loading branch information
HypeMC committed May 10, 2022
1 parent 85b5207 commit 4694fc2
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 17 deletions.
15 changes: 13 additions & 2 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@

namespace Symfony\Bundle\MonologBundle\DependencyInjection;

use Monolog\Logger;
use Symfony\Component\Config\Definition\BaseNode;
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 Monolog\Logger;

/**
* This class contains the configuration information for the bundle
Expand Down Expand Up @@ -426,7 +426,18 @@ public function getConfigTreeBuilder()
->scalarNode('app_name')->defaultNull()->end()
->booleanNode('fill_extra_context')->defaultFalse()->end() // sentry
->booleanNode('include_stacktraces')->defaultFalse()->end()
->booleanNode('process_psr_3_messages')->defaultNull()->end()
->arrayNode('process_psr_3_messages')
->addDefaultsIfNotSet()
->beforeNormalization()
->ifTrue(static function ($v) { return !\is_array($v); })
->then(static function ($v) { return ['enabled' => $v]; })
->end()
->children()
->booleanNode('enabled')->defaultNull()->end()
->scalarNode('date_format')->end()
->booleanNode('remove_used_context_fields')->end()
->end()
->end()
->scalarNode('path')->defaultValue('%kernel.logs_dir%/%kernel.environment%.log')->end() // stream and rotating
->scalarNode('file_permission') // stream and rotating
->defaultNull()
Expand Down
57 changes: 43 additions & 14 deletions DependencyInjection/MonologExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@

use Monolog\Attribute\AsMonologProcessor;
use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
use Monolog\Handler\HandlerInterface;
use Monolog\Logger;
use Monolog\Processor\ProcessorInterface;
use Monolog\Handler\HandlerInterface;
use Monolog\Processor\PsrLogMessageProcessor;
use Monolog\ResettableInterface;
use Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy;
use Symfony\Bridge\Monolog\Processor\SwitchUserTokenProcessor;
Expand Down Expand Up @@ -203,21 +204,13 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler
$definition->setConfigurator(['Symfony\\Bundle\\MonologBundle\\MonologBundle', 'includeStacktraces']);
}

if (null === $handler['process_psr_3_messages']) {
$handler['process_psr_3_messages'] = !isset($handler['handler']) && !$handler['members'];
if (null === $handler['process_psr_3_messages']['enabled']) {
$handler['process_psr_3_messages']['enabled'] = !isset($handler['handler']) && !$handler['members'];
}

if ($handler['process_psr_3_messages']) {
if (method_exists($handlerClass, 'pushProcessor')) {
$processorId = 'monolog.processor.psr_log_message';
if (!$container->hasDefinition($processorId)) {
$processor = new Definition('Monolog\\Processor\\PsrLogMessageProcessor');
$processor->setPublic(false);
$container->setDefinition($processorId, $processor);
}

$definition->addMethodCall('pushProcessor', [new Reference($processorId)]);
}
if ($handler['process_psr_3_messages']['enabled'] && method_exists($handlerClass, 'pushProcessor')) {
$processorId = $this->buildPsrLogMessageProcessor($container, $handler['process_psr_3_messages']);
$definition->addMethodCall('pushProcessor', [new Reference($processorId)]);
}

switch ($handler['type']) {
Expand Down Expand Up @@ -1040,4 +1033,40 @@ private function getHandlerClassByType($handlerType)

return $typeToClassMapping[$handlerType];
}

private function buildPsrLogMessageProcessor(ContainerBuilder $container, array $processorOptions): string
{
static $hasConstructorArguments;

if (!isset($hasConstructorArguments)) {
$reflectionConstructor = (new \ReflectionClass(PsrLogMessageProcessor::class))->getConstructor();
$hasConstructorArguments = null !== $reflectionConstructor && $reflectionConstructor->getNumberOfParameters() > 0;
unset($reflectionConstructor);
}

$processorId = 'monolog.processor.psr_log_message';
$processorArguments = [];

unset($processorOptions['enabled']);

if (!empty($processorOptions)) {
if (!$hasConstructorArguments) {
throw new \RuntimeException('Monolog 1.26 or higher is required for the "date_format" and "remove_used_context_fields" options to be used.');
}
$processorArguments = [
$processorOptions['date_format'] ?? null,
$processorOptions['remove_used_context_fields'] ?? false,
];
$processorId .= '.'.ContainerBuilder::hash($processorArguments);
}

if (!$container->hasDefinition($processorId)) {
$processor = new Definition(PsrLogMessageProcessor::class);
$processor->setPublic(false);
$processor->setArguments($processorArguments);
$container->setDefinition($processorId, $processor);
}

return $processorId;
}
}
9 changes: 8 additions & 1 deletion Resources/config/schema/monolog-1.0.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<xsd:element name="accepted-level" type="level" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="to-email" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="header" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="process-psr-3-messages" type="process-psr-3-messages" minOccurs="0" maxOccurs="1" />
</xsd:sequence>
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="priority" type="xsd:integer" />
Expand Down Expand Up @@ -192,7 +193,13 @@

<xsd:complexType name="headers">
<xsd:sequence>
<xsd:any minOccurs="0" processContents="lax"/>
<xsd:any minOccurs="0" processContents="lax" />
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="process-psr-3-messages">
<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:attribute name="date-format" type="xsd:string" />
<xsd:attribute name="remove-used-context-fields" type="xsd:boolean" />
</xsd:complexType>
</xsd:schema>
35 changes: 35 additions & 0 deletions Tests/DependencyInjection/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,41 @@ public function testConsoleFormatterOptionsRename()
$this->assertArrayNotHasKey('console_formater_options', $config['handlers']['both2']);
}

/**
* @dataProvider processPsr3MessagesProvider
*/
public function testWithProcessPsr3Messages(array $configuration, array $processedConfiguration): void
{
$configs = [
[
'handlers' => [
'main' => ['type' => 'stream'] + $configuration,
],
],
];

$config = $this->process($configs);

$this->assertEquals($processedConfiguration, $config['handlers']['main']['process_psr_3_messages']);
}

public function processPsr3MessagesProvider(): iterable
{
yield 'Not specified' => [[], ['enabled' => null]];
yield 'Null' => [['process_psr_3_messages' => null], ['enabled' => true]];
yield 'True' => [['process_psr_3_messages' => true], ['enabled' => true]];
yield 'False' => [['process_psr_3_messages' => false], ['enabled' => false]];

yield 'Date format' => [
['process_psr_3_messages' => ['date_format' => 'Y']],
['date_format' => 'Y', 'enabled' => null],
];
yield 'Enabled false & remove used' => [
['process_psr_3_messages' => ['enabled' => false, 'remove_used_context_fields' => true]],
['enabled' => false, 'remove_used_context_fields' => true],
];
}

/**
* Processes an array of configurations and returns a compiled version.
*
Expand Down
50 changes: 50 additions & 0 deletions Tests/DependencyInjection/FixtureMonologExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Bundle\MonologBundle\Tests\DependencyInjection;

use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
use Monolog\Processor\PsrLogMessageProcessor;
use Symfony\Bridge\Monolog\Processor\SwitchUserTokenProcessor;
use Symfony\Bundle\MonologBundle\DependencyInjection\Compiler\LoggerChannelPass;
use Symfony\Bundle\MonologBundle\DependencyInjection\MonologExtension;
Expand Down Expand Up @@ -280,6 +281,55 @@ public function testPsr3MessageProcessingDisabled()
$this->assertNotContainsEquals(['pushProcessor', [new Reference('monolog.processor.psr_log_message')]], $methodCalls, 'The PSR-3 processor should not be enabled');
}

public function testPsrLogMessageProcessorHasConstructorArguments(): void
{
$reflectionConstructor = (new \ReflectionClass(PsrLogMessageProcessor::class))->getConstructor();
if (null === $reflectionConstructor || $reflectionConstructor->getNumberOfParameters() <= 0) {
$this->markTestSkipped('Monolog >= 1.26 is needed.');
}

$container = $this->getContainer('process_psr_3_messages_with_arguments');

$processors = [
'monolog.processor.psr_log_message' => ['name' => 'without_arguments', 'arguments' => []],
'monolog.processor.psr_log_message.'.ContainerBuilder::hash($arguments = ['Y', false]) => [
'name' => 'with_arguments',
'arguments' => $arguments,
],
];
foreach ($processors as $processorId => $settings) {
$this->assertTrue($container->hasDefinition($processorId));
$processor = $container->getDefinition($processorId);
$this->assertDICConstructorArguments($processor, $settings['arguments']);

$this->assertTrue($container->hasDefinition($handlerId = 'monolog.handler.'.$settings['name']));
$handler = $container->getDefinition($handlerId);
$this->assertDICDefinitionMethodCallAt(0, $handler, 'pushProcessor', [new Reference($processorId)]);
}
}

public function testPsrLogMessageProcessorDoesNotHaveConstructorArguments(): void
{
$reflectionConstructor = (new \ReflectionClass(PsrLogMessageProcessor::class))->getConstructor();
if (null !== $reflectionConstructor && $reflectionConstructor->getNumberOfParameters() > 0) {
$this->markTestSkipped('Monolog < 1.26 is needed.');
}

$container = $this->getContainer('process_psr_3_messages_without_arguments');

$this->assertTrue($container->hasDefinition($processorId = 'monolog.processor.psr_log_message'));
$processor = $container->getDefinition($processorId);
$this->assertDICConstructorArguments($processor, []);

$this->assertTrue($container->hasDefinition($handlerId = 'monolog.handler.without_arguments'));
$handler = $container->getDefinition($handlerId);
$this->assertDICDefinitionMethodCallAt(0, $handler, 'pushProcessor', [new Reference($processorId)]);

$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Monolog 1.26 or higher is required for the "date_format" and "remove_used_context_fields" options to be used.');
$this->getContainer('process_psr_3_messages_with_arguments');
}

public function testNativeMailer()
{
$container = $this->getContainer('native_mailer');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?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:handler name="with_arguments" type="stream">
<monolog:process-psr-3-messages date-format="Y" />
</monolog:handler>
<monolog:handler name="without_arguments" type="stream">
<monolog:process-psr-3-messages enabled="true" />
</monolog:handler>
</monolog:config>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?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:handler name="without_arguments" type="stream">
<monolog:process-psr-3-messages enabled="true" />
</monolog:handler>
</monolog:config>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
monolog:
handlers:
with_arguments:
type: stream
process_psr_3_messages:
date_format: 'Y'
without_arguments:
type: stream
process_psr_3_messages:
enabled: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
monolog:
handlers:
without_arguments:
type: stream
process_psr_3_messages:
enabled: true

0 comments on commit 4694fc2

Please sign in to comment.