feature #36621 Log deprecations on a dedicated Monolog channel (l-vo)
This PR was squashed before being merged into the 5.1-dev branch.
Discussion
----------
Log deprecations on a dedicated Monolog channel
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| Deprecations? | no
| Tickets | https://github.com/orgs/symfony/projects/1#card-35233930
| License | MIT
| Doc PR |
This PR allows to activate a specific channel for deprecations.
## Base configuration
```yaml
monolog:
handlers:
#...
deprecation:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.deprecations.log"
deprecation_filter:
type: filter
handler: deprecation
max_level: info
channels: ["php"]
```
## Deprecation specific channel enabled:
```yaml
monolog:
channels: ['deprecation']
handlers:
#...
deprecation:
type: stream
channels: ["deprecation"]
path: "%kernel.logs_dir%/%kernel.environment%.deprecations.log"
```
Commits
-------
3d415cb70d
Log deprecations on a dedicated Monolog channel
This commit is contained in:
commit
55706f75ac
@ -15,12 +15,13 @@
|
|||||||
<tag name="kernel.event_subscriber" />
|
<tag name="kernel.event_subscriber" />
|
||||||
<tag name="monolog.logger" channel="php" />
|
<tag name="monolog.logger" channel="php" />
|
||||||
<argument>null</argument><!-- Exception handler -->
|
<argument>null</argument><!-- Exception handler -->
|
||||||
<argument type="service" id="logger" on-invalid="null" />
|
<argument type="service" id="monolog.logger.php" on-invalid="null" />
|
||||||
<argument>null</argument><!-- Log levels map for enabled error levels -->
|
<argument>null</argument><!-- Log levels map for enabled error levels -->
|
||||||
<argument>%debug.error_handler.throw_at%</argument>
|
<argument>%debug.error_handler.throw_at%</argument>
|
||||||
<argument>%kernel.debug%</argument>
|
<argument>%kernel.debug%</argument>
|
||||||
<argument type="service" id="debug.file_link_formatter" />
|
<argument type="service" id="debug.file_link_formatter" />
|
||||||
<argument>%kernel.debug%</argument>
|
<argument>%kernel.debug%</argument>
|
||||||
|
<argument type="service" id="monolog.logger.deprecation" on-invalid="null" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="debug.file_link_formatter" class="Symfony\Component\HttpKernel\Debug\FileLinkFormatter">
|
<service id="debug.file_link_formatter" class="Symfony\Component\HttpKernel\Debug\FileLinkFormatter">
|
||||||
|
@ -425,7 +425,7 @@ abstract class FrameworkExtensionTest extends TestCase
|
|||||||
$container = $this->createContainerFromFile('php_errors_enabled');
|
$container = $this->createContainerFromFile('php_errors_enabled');
|
||||||
|
|
||||||
$definition = $container->getDefinition('debug.debug_handlers_listener');
|
$definition = $container->getDefinition('debug.debug_handlers_listener');
|
||||||
$this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1));
|
$this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1));
|
||||||
$this->assertNull($definition->getArgument(2));
|
$this->assertNull($definition->getArgument(2));
|
||||||
$this->assertSame(-1, $container->getParameter('debug.error_handler.throw_at'));
|
$this->assertSame(-1, $container->getParameter('debug.error_handler.throw_at'));
|
||||||
}
|
}
|
||||||
@ -445,7 +445,7 @@ abstract class FrameworkExtensionTest extends TestCase
|
|||||||
$container = $this->createContainerFromFile('php_errors_log_level');
|
$container = $this->createContainerFromFile('php_errors_log_level');
|
||||||
|
|
||||||
$definition = $container->getDefinition('debug.debug_handlers_listener');
|
$definition = $container->getDefinition('debug.debug_handlers_listener');
|
||||||
$this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1));
|
$this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1));
|
||||||
$this->assertSame(8, $definition->getArgument(2));
|
$this->assertSame(8, $definition->getArgument(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
5.2.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* allowed to use a specific logger channel for deprecations
|
||||||
|
|
||||||
5.1.0
|
5.1.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ class DebugHandlersListener implements EventSubscriberInterface
|
|||||||
{
|
{
|
||||||
private $exceptionHandler;
|
private $exceptionHandler;
|
||||||
private $logger;
|
private $logger;
|
||||||
|
private $deprecationLogger;
|
||||||
private $levels;
|
private $levels;
|
||||||
private $throwAt;
|
private $throwAt;
|
||||||
private $scream;
|
private $scream;
|
||||||
@ -48,7 +49,7 @@ class DebugHandlersListener implements EventSubscriberInterface
|
|||||||
* @param string|FileLinkFormatter|null $fileLinkFormat The format for links to source files
|
* @param string|FileLinkFormatter|null $fileLinkFormat The format for links to source files
|
||||||
* @param bool $scope Enables/disables scoping mode
|
* @param bool $scope Enables/disables scoping mode
|
||||||
*/
|
*/
|
||||||
public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = E_ALL, ?int $throwAt = E_ALL, bool $scream = true, $fileLinkFormat = null, bool $scope = true)
|
public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = E_ALL, ?int $throwAt = E_ALL, bool $scream = true, $fileLinkFormat = null, bool $scope = true, LoggerInterface $deprecationLogger = null)
|
||||||
{
|
{
|
||||||
$this->exceptionHandler = $exceptionHandler;
|
$this->exceptionHandler = $exceptionHandler;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
@ -57,6 +58,7 @@ class DebugHandlersListener implements EventSubscriberInterface
|
|||||||
$this->scream = $scream;
|
$this->scream = $scream;
|
||||||
$this->fileLinkFormat = $fileLinkFormat;
|
$this->fileLinkFormat = $fileLinkFormat;
|
||||||
$this->scope = $scope;
|
$this->scope = $scope;
|
||||||
|
$this->deprecationLogger = $deprecationLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,31 +78,30 @@ class DebugHandlersListener implements EventSubscriberInterface
|
|||||||
$handler = \is_array($handler) ? $handler[0] : null;
|
$handler = \is_array($handler) ? $handler[0] : null;
|
||||||
restore_exception_handler();
|
restore_exception_handler();
|
||||||
|
|
||||||
if ($this->logger || null !== $this->throwAt) {
|
if ($handler instanceof ErrorHandler) {
|
||||||
if ($handler instanceof ErrorHandler) {
|
if ($this->logger || $this->deprecationLogger) {
|
||||||
if ($this->logger) {
|
$this->setDefaultLoggers($handler);
|
||||||
$handler->setDefaultLogger($this->logger, $this->levels);
|
if (\is_array($this->levels)) {
|
||||||
if (\is_array($this->levels)) {
|
$levels = 0;
|
||||||
$levels = 0;
|
foreach ($this->levels as $type => $log) {
|
||||||
foreach ($this->levels as $type => $log) {
|
$levels |= $type;
|
||||||
$levels |= $type;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$levels = $this->levels;
|
|
||||||
}
|
}
|
||||||
if ($this->scream) {
|
} else {
|
||||||
$handler->screamAt($levels);
|
$levels = $this->levels;
|
||||||
}
|
|
||||||
if ($this->scope) {
|
|
||||||
$handler->scopeAt($levels & ~E_USER_DEPRECATED & ~E_DEPRECATED);
|
|
||||||
} else {
|
|
||||||
$handler->scopeAt(0, true);
|
|
||||||
}
|
|
||||||
$this->logger = $this->levels = null;
|
|
||||||
}
|
}
|
||||||
if (null !== $this->throwAt) {
|
|
||||||
$handler->throwAt($this->throwAt, true);
|
if ($this->scream) {
|
||||||
|
$handler->screamAt($levels);
|
||||||
}
|
}
|
||||||
|
if ($this->scope) {
|
||||||
|
$handler->scopeAt($levels & ~E_USER_DEPRECATED & ~E_DEPRECATED);
|
||||||
|
} else {
|
||||||
|
$handler->scopeAt(0, true);
|
||||||
|
}
|
||||||
|
$this->logger = $this->deprecationLogger = $this->levels = null;
|
||||||
|
}
|
||||||
|
if (null !== $this->throwAt) {
|
||||||
|
$handler->throwAt($this->throwAt, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$this->exceptionHandler) {
|
if (!$this->exceptionHandler) {
|
||||||
@ -135,6 +136,34 @@ class DebugHandlersListener implements EventSubscriberInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function setDefaultLoggers(ErrorHandler $handler): void
|
||||||
|
{
|
||||||
|
if (\is_array($this->levels)) {
|
||||||
|
$levelsDeprecatedOnly = [];
|
||||||
|
$levelsWithoutDeprecated = [];
|
||||||
|
foreach ($this->levels as $type => $log) {
|
||||||
|
if (E_DEPRECATED == $type || E_USER_DEPRECATED == $type) {
|
||||||
|
$levelsDeprecatedOnly[$type] = $log;
|
||||||
|
} else {
|
||||||
|
$levelsWithoutDeprecated[$type] = $log;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$levelsDeprecatedOnly = $this->levels & (E_DEPRECATED | E_USER_DEPRECATED);
|
||||||
|
$levelsWithoutDeprecated = $this->levels & ~E_DEPRECATED & ~E_USER_DEPRECATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
$defaultLoggerLevels = $this->levels;
|
||||||
|
if ($this->deprecationLogger && $levelsDeprecatedOnly) {
|
||||||
|
$handler->setDefaultLogger($this->deprecationLogger, $levelsDeprecatedOnly);
|
||||||
|
$defaultLoggerLevels = $levelsWithoutDeprecated;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->logger && $defaultLoggerLevels) {
|
||||||
|
$handler->setDefaultLogger($this->logger, $defaultLoggerLevels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function getSubscribedEvents(): array
|
public static function getSubscribedEvents(): array
|
||||||
{
|
{
|
||||||
$events = [KernelEvents::REQUEST => ['configure', 2048]];
|
$events = [KernelEvents::REQUEST => ['configure', 2048]];
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace Symfony\Component\HttpKernel\Tests\EventListener;
|
namespace Symfony\Component\HttpKernel\Tests\EventListener;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use Psr\Log\LogLevel;
|
use Psr\Log\LogLevel;
|
||||||
use Symfony\Component\Console\Application;
|
use Symfony\Component\Console\Application;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
@ -150,4 +151,89 @@ class DebugHandlersListenerTest extends TestCase
|
|||||||
|
|
||||||
$this->assertSame($userHandler, $eHandler->setExceptionHandler('var_dump'));
|
$this->assertSame($userHandler, $eHandler->setExceptionHandler('var_dump'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function provideLevelsAssignedToLoggers(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[false, false, '0', null, null],
|
||||||
|
[false, false, E_ALL, null, null],
|
||||||
|
[false, false, [], null, null],
|
||||||
|
[false, false, [E_WARNING => LogLevel::WARNING, E_USER_DEPRECATED => LogLevel::NOTICE], null, null],
|
||||||
|
|
||||||
|
[true, false, E_ALL, E_ALL, null],
|
||||||
|
[true, false, E_DEPRECATED, E_DEPRECATED, null],
|
||||||
|
[true, false, [], null, null],
|
||||||
|
[true, false, [E_WARNING => LogLevel::WARNING, E_DEPRECATED => LogLevel::NOTICE], [E_WARNING => LogLevel::WARNING, E_DEPRECATED => LogLevel::NOTICE], null],
|
||||||
|
|
||||||
|
[false, true, '0', null, null],
|
||||||
|
[false, true, E_ALL, null, E_DEPRECATED | E_USER_DEPRECATED],
|
||||||
|
[false, true, E_ERROR, null, null],
|
||||||
|
[false, true, [], null, null],
|
||||||
|
[false, true, [E_ERROR => LogLevel::ERROR, E_DEPRECATED => LogLevel::DEBUG], null, [E_DEPRECATED => LogLevel::DEBUG]],
|
||||||
|
|
||||||
|
[true, true, '0', null, null],
|
||||||
|
[true, true, E_ALL, E_ALL & ~(E_DEPRECATED | E_USER_DEPRECATED), E_DEPRECATED | E_USER_DEPRECATED],
|
||||||
|
[true, true, E_ERROR, E_ERROR, null],
|
||||||
|
[true, true, E_USER_DEPRECATED, null, E_USER_DEPRECATED],
|
||||||
|
[true, true, [E_ERROR => LogLevel::ERROR, E_DEPRECATED => LogLevel::DEBUG], [E_ERROR => LogLevel::ERROR], [E_DEPRECATED => LogLevel::DEBUG]],
|
||||||
|
[true, true, [E_ERROR => LogLevel::ALERT], [E_ERROR => LogLevel::ALERT], null],
|
||||||
|
[true, true, [E_USER_DEPRECATED => LogLevel::NOTICE], null, [E_USER_DEPRECATED => LogLevel::NOTICE]],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideLevelsAssignedToLoggers
|
||||||
|
*
|
||||||
|
* @param array|string $levels
|
||||||
|
* @param array|string|null $expectedLoggerLevels
|
||||||
|
* @param array|string|null $expectedDeprecationLoggerLevels
|
||||||
|
*/
|
||||||
|
public function testLevelsAssignedToLoggers(bool $hasLogger, bool $hasDeprecationLogger, $levels, $expectedLoggerLevels, $expectedDeprecationLoggerLevels)
|
||||||
|
{
|
||||||
|
if (!class_exists(ErrorHandler::class)) {
|
||||||
|
$this->markTestSkipped('ErrorHandler component is required to run this test.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$handler = $this->createMock(ErrorHandler::class);
|
||||||
|
|
||||||
|
$expectedCalls = [];
|
||||||
|
$logger = null;
|
||||||
|
|
||||||
|
$deprecationLogger = null;
|
||||||
|
if ($hasDeprecationLogger) {
|
||||||
|
$deprecationLogger = $this->createMock(LoggerInterface::class);
|
||||||
|
if (null !== $expectedDeprecationLoggerLevels) {
|
||||||
|
$expectedCalls[] = [$deprecationLogger, $expectedDeprecationLoggerLevels];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($hasLogger) {
|
||||||
|
$logger = $this->createMock(LoggerInterface::class);
|
||||||
|
if (null !== $expectedLoggerLevels) {
|
||||||
|
$expectedCalls[] = [$logger, $expectedLoggerLevels];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$handler
|
||||||
|
->expects($this->exactly(\count($expectedCalls)))
|
||||||
|
->method('setDefaultLogger')
|
||||||
|
->withConsecutive(...$expectedCalls);
|
||||||
|
|
||||||
|
$sut = new DebugHandlersListener(null, $logger, $levels, null, true, null, true, $deprecationLogger);
|
||||||
|
$prevHander = set_exception_handler([$handler, 'handleError']);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$handler
|
||||||
|
->method('handleError')
|
||||||
|
->willReturnCallback(function () use ($prevHander) {
|
||||||
|
$prevHander(...\func_get_args());
|
||||||
|
});
|
||||||
|
|
||||||
|
$sut->configure();
|
||||||
|
set_exception_handler($prevHander);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
set_exception_handler($prevHander);
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user