Skip to content

Commit

Permalink
Fix compatibility with Monolog 3
Browse files Browse the repository at this point in the history
  • Loading branch information
HypeMC committed Sep 18, 2022
1 parent 7a32ad7 commit fa45a83
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 90 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
],
"require": {
"php": ">=7.2",
"monolog/monolog": "^1.25.1 || ^2",
"monolog/monolog": "^1.25.1 || ^2 || ^3",
"symfony/config": "^4.4 || ^5.2 || ^6.0",
"symfony/console": "^4.4 || ^5.2 || ^6.0",
"symfony/dependency-injection": "^4.4 || ^5.2 || ^6.0",
Expand Down
4 changes: 2 additions & 2 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ parameters:
path: src/HandlerFactory/AbstractHandlerFactory.php

-
message: '#^Parameter \#1 \$record of method Symfony\\Bridge\\Monolog\\Handler\\ConsoleHandler\:\:handle\(\) expects Monolog\\LogRecord, array\<string, array\|DateTimeImmutable\|int\|string\> given\.$#'
message: '#^Comparison operation "\>\=" between 3 and 3 is always true\.$#'
count: 1
path: src/Handler/ConsoleHandler.php

-
message: '#^Parameter \#1 \$record of method Symfony\\Bridge\\Monolog\\Handler\\ConsoleHandler\:\:isHandling\(\) expects Monolog\\LogRecord, array\<string, int\> given\.$#'
message: '#^Else branch is unreachable because previous condition is always true\.$#'
count: 1
path: src/Handler/ConsoleHandler.php
5 changes: 5 additions & 0 deletions phpunit-deprecation-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
"message": "Function libxml_disable_entity_loader() is deprecated",
"count": 4
},
{
"location": "Bizkit\\LoggableCommandBundle\\Tests\\DependencyInjection\\BizkitLoggableCommandExtensionTest::testConsoleHandlerCanBeInstantiated",
"message": "Function libxml_disable_entity_loader() is deprecated",
"count": 8
},
{
"location": "Bizkit\\LoggableCommandBundle\\Tests\\DependencyInjection\\BizkitLoggableCommandExtensionTest::testAutoconfigurationIsRegistered",
"message": "Function libxml_disable_entity_loader() is deprecated",
Expand Down
59 changes: 53 additions & 6 deletions src/Handler/ConsoleHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,63 @@
use Monolog\Handler\FormattableHandlerInterface;
use Monolog\Handler\HandlerInterface;
use Monolog\Handler\ProcessableHandlerInterface;
use Monolog\Level;
use Monolog\Logger;
use Monolog\LogRecord;
use Psr\Log\LogLevel;
use Symfony\Bridge\Monolog\Handler\ConsoleHandler as BaseConsoleHandler;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

if (Logger::API >= 3) {
trait CompatibilityHandlerTrait
{
public function handle(LogRecord $record): bool
{
return $this->doHandle($record);
}

public function isHandling(LogRecord $record): bool
{
return $this->doIsHandling($record);
}

public function getLevel(): Level
{
return $this->doGetLevel();
}
}
} else {
trait CompatibilityHandlerTrait
{
public function handle(array $record): bool
{
return $this->doHandle($record);
}

public function isHandling(array $record): bool
{
return $this->doIsHandling($record);
}

public function getLevel(): int
{
return $this->doGetLevel();
}
}
}

/**
* Unlike Symfony's ConsoleHandler which sends everything to stderr if available,
* this one sends to stdout or stderr depending on the {@see ConsoleHandler::$stdErrThreshold} setting.
*/
final class ConsoleHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface, EventSubscriberInterface
{
use CompatibilityHandlerTrait;

/**
* @var BaseConsoleHandler
*/
Expand All @@ -31,7 +74,7 @@ final class ConsoleHandler extends AbstractHandler implements ProcessableHandler
/**
* @var int
*/
private $stdErrThreshold = Logger::WARNING;
private $stdErrThreshold;

/**
* @var OutputInterface|null
Expand All @@ -46,11 +89,15 @@ final class ConsoleHandler extends AbstractHandler implements ProcessableHandler
public function __construct(BaseConsoleHandler $innerHandler)
{
$this->innerHandler = $innerHandler;
$this->setStdErrThreshold(Logger::toMonologLevel(LogLevel::WARNING));
}

public function setStdErrThreshold(int $stdErrThreshold): void
/**
* @param int|Level $stdErrThreshold
*/
public function setStdErrThreshold($stdErrThreshold): void
{
$this->stdErrThreshold = $stdErrThreshold;
$this->stdErrThreshold = $stdErrThreshold instanceof Level ? $stdErrThreshold->value : $stdErrThreshold;
}

public function setStandardOutput(OutputInterface $standardOutput): void
Expand Down Expand Up @@ -96,7 +143,7 @@ public function onTerminate(ConsoleTerminateEvent $event): void
$this->close();
}

public function handle(array $record): bool
private function doHandle($record): bool
{
$this->innerHandler->setOutput(
$record['level'] < $this->stdErrThreshold ? $this->standardOutput : $this->errorOutput
Expand All @@ -110,7 +157,7 @@ public static function getSubscribedEvents(): array
return BaseConsoleHandler::getSubscribedEvents();
}

public function isHandling(array $record): bool
private function doIsHandling($record): bool
{
return $this->innerHandler->isHandling($record);
}
Expand Down Expand Up @@ -156,7 +203,7 @@ public function setLevel($level): AbstractHandler
return $this;
}

public function getLevel(): int
private function doGetLevel()
{
return $this->innerHandler->getLevel();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\DocParser;
use Monolog\Logger;
use Psr\Log\LogLevel;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBag;
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
Expand All @@ -34,7 +34,7 @@ protected function setUp(): void

public function testProviderReturnsExpectedConfigWhenAnnotationIsFound(): void
{
$handlerOptions = ['filename' => 'annotation-test', 'level' => Logger::CRITICAL, 'max_files' => 4];
$handlerOptions = ['filename' => 'annotation-test', 'level' => LogLevel::CRITICAL, 'max_files' => 4];

$provider = $this->createConfigurationProvider(
$this->createContainerBagWithResolveValueMethodCalled($handlerOptions)
Expand All @@ -48,7 +48,7 @@ public function testProviderReturnsExpectedConfigWhenAnnotationIsFound(): void

public function testProviderReturnsExpectedConfigWhenParentAndChildAnnotationsAreFound(): void
{
$handlerOptions = ['filename' => 'child-annotation-test', 'level' => Logger::CRITICAL, 'max_files' => 4];
$handlerOptions = ['filename' => 'child-annotation-test', 'level' => LogLevel::CRITICAL, 'max_files' => 4];

$provider = $this->createConfigurationProvider(
$this->createContainerBagWithResolveValueMethodCalled($handlerOptions)
Expand All @@ -62,7 +62,7 @@ public function testProviderReturnsExpectedConfigWhenParentAndChildAnnotationsAr

public function testProviderReturnsExpectedConfigWhenParentAnnotationIsFound(): void
{
$handlerOptions = ['filename' => 'annotation-test', 'level' => Logger::CRITICAL, 'max_files' => 4];
$handlerOptions = ['filename' => 'annotation-test', 'level' => LogLevel::CRITICAL, 'max_files' => 4];

$provider = $this->createConfigurationProvider(
$this->createContainerBagWithResolveValueMethodCalled($handlerOptions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use Bizkit\LoggableCommandBundle\Tests\ConfigurationProvider\Fixtures\DummyLoggableOutputWithAttribute;
use Bizkit\LoggableCommandBundle\Tests\ConfigurationProvider\Fixtures\DummyLoggableOutputWithAttributeAndParam;
use Bizkit\LoggableCommandBundle\Tests\TestCase;
use Monolog\Logger;
use Psr\Log\LogLevel;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBag;
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
Expand All @@ -26,7 +26,7 @@ final class AttributeConfigurationProviderTest extends TestCase
{
public function testProviderReturnsExpectedConfigWhenAttributeIsFound(): void
{
$handlerOptions = ['filename' => 'attribute-test', 'level' => Logger::EMERGENCY, 'bubble' => true];
$handlerOptions = ['filename' => 'attribute-test', 'level' => LogLevel::EMERGENCY, 'bubble' => true];

$provider = $this->createConfigurationProvider(
$this->createContainerBagWithResolveValueMethodCalled($handlerOptions)
Expand All @@ -40,7 +40,7 @@ public function testProviderReturnsExpectedConfigWhenAttributeIsFound(): void

public function testProviderReturnsExpectedConfigWhenParentAndChildAttributesAreFound(): void
{
$handlerOptions = ['filename' => 'child-attribute-test', 'level' => Logger::EMERGENCY, 'bubble' => true];
$handlerOptions = ['filename' => 'child-attribute-test', 'level' => LogLevel::EMERGENCY, 'bubble' => true];

$provider = $this->createConfigurationProvider(
$this->createContainerBagWithResolveValueMethodCalled($handlerOptions)
Expand All @@ -54,7 +54,7 @@ public function testProviderReturnsExpectedConfigWhenParentAndChildAttributesAre

public function testProviderReturnsExpectedConfigWhenParentAttributeIsFound(): void
{
$handlerOptions = ['filename' => 'attribute-test', 'level' => Logger::EMERGENCY, 'bubble' => true];
$handlerOptions = ['filename' => 'attribute-test', 'level' => LogLevel::EMERGENCY, 'bubble' => true];

$provider = $this->createConfigurationProvider(
$this->createContainerBagWithResolveValueMethodCalled($handlerOptions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
use Bizkit\LoggableCommandBundle\ConfigurationProvider\Attribute\LoggableOutput;
use Bizkit\LoggableCommandBundle\LoggableOutput\LoggableOutputInterface;
use Bizkit\LoggableCommandBundle\LoggableOutput\LoggableOutputTrait;
use Monolog\Logger;
use Psr\Log\LogLevel;

/**
* @LoggableOutput(filename="annotation-test", level=Logger::CRITICAL, maxFiles=4)
* @LoggableOutput(filename="annotation-test", level=LogLevel::CRITICAL, maxFiles=4)
*/
class DummyLoggableOutputWithAnnotation implements LoggableOutputInterface
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
use Bizkit\LoggableCommandBundle\ConfigurationProvider\Attribute\LoggableOutput;
use Bizkit\LoggableCommandBundle\LoggableOutput\LoggableOutputInterface;
use Bizkit\LoggableCommandBundle\LoggableOutput\LoggableOutputTrait;
use Monolog\Logger;
use Psr\Log\LogLevel;

#[LoggableOutput(filename: 'attribute-test', level: Logger::EMERGENCY, bubble: true)]
#[LoggableOutput(filename: 'attribute-test', level: LogLevel::EMERGENCY, bubble: true)]
class DummyLoggableOutputWithAttribute implements LoggableOutputInterface
{
use LoggableOutputTrait;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use Bizkit\LoggableCommandBundle\LoggableOutput\LoggableOutputInterface;
use Bizkit\LoggableCommandBundle\Tests\ConfigurationProvider\Fixtures\DummyLoggableOutput;
use Bizkit\LoggableCommandBundle\Tests\TestCase;
use Monolog\Logger;
use Psr\Log\LogLevel;

/**
* @covers \Bizkit\LoggableCommandBundle\ConfigurationProvider\MergedConfigurationProvider
Expand All @@ -22,18 +22,18 @@ public function testConfigsAreMergedAsExpected(): void

$provider = $this->createConfigurationProvider(
$loggableOutput,
['filename' => 'annotation-test', 'level' => Logger::CRITICAL, 'max_files' => 4, 'extra_options' => [
['filename' => 'annotation-test', 'level' => LogLevel::CRITICAL, 'max_files' => 4, 'extra_options' => [
'foo' => 'one',
'bar' => 'two',
]],
['filename' => 'attribute-test', 'level' => Logger::EMERGENCY, 'bubble' => true, 'extra_options' => [
['filename' => 'attribute-test', 'level' => LogLevel::EMERGENCY, 'bubble' => true, 'extra_options' => [
'foo' => 'new one',
'baz' => 'three',
]]
);

$this->assertSame(
['filename' => 'annotation-test', 'level' => Logger::CRITICAL, 'max_files' => 4, 'bubble' => true, 'extra_options' => [
['filename' => 'annotation-test', 'level' => LogLevel::CRITICAL, 'max_files' => 4, 'bubble' => true, 'extra_options' => [
'foo' => 'one',
'bar' => 'two',
'baz' => 'three',
Expand Down
49 changes: 41 additions & 8 deletions tests/DependencyInjection/BizkitLoggableCommandExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
use Bizkit\LoggableCommandBundle\Tests\DependencyInjection\Fixtures\DummyLoggableOutput;
use Bizkit\LoggableCommandBundle\Tests\TestCase;
use Doctrine\Common\Annotations\Annotation;
use Monolog\Level;
use Monolog\Logger;
use Monolog\Processor\PsrLogMessageProcessor;
use Psr\Log\LogLevel;
use Symfony\Bundle\MonologBundle\DependencyInjection\MonologExtension;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\Compiler\ResolveInstanceofConditionalsPass;
Expand Down Expand Up @@ -180,19 +182,25 @@ public function testArgumentsAreReplacedAsExpected(): void

$this->assertTrue($definition->hasMethodCall('setStdErrThreshold'));
$methodCalls = array_column($definition->getMethodCalls(), 1, 0);
$this->assertSame([Logger::CRITICAL], $methodCalls['setStdErrThreshold']);
$this->assertSame([Logger::toMonologLevel(LogLevel::CRITICAL)], $methodCalls['setStdErrThreshold']);

$definition = $container->getDefinition((string) $definition->getArgument(0));

$this->assertFalse($definition->getArgument(1));

$this->assertSame([
OutputInterface::VERBOSITY_NORMAL => Logger::INFO,
OutputInterface::VERBOSITY_VERBOSE => Logger::INFO,
OutputInterface::VERBOSITY_QUIET => Logger::ERROR,
OutputInterface::VERBOSITY_VERY_VERBOSE => Logger::INFO,
OutputInterface::VERBOSITY_DEBUG => Logger::DEBUG,
], $definition->getArgument(2));
$expectedVerbosityLevels = array_map(static function (string $level): int {
/** @var int|Level $level */
$level = Logger::toMonologLevel($level);

return $level instanceof Level ? $level->value : $level;
}, [
OutputInterface::VERBOSITY_NORMAL => LogLevel::INFO,
OutputInterface::VERBOSITY_VERBOSE => LogLevel::INFO,
OutputInterface::VERBOSITY_QUIET => LogLevel::ERROR,
OutputInterface::VERBOSITY_VERY_VERBOSE => LogLevel::INFO,
OutputInterface::VERBOSITY_DEBUG => LogLevel::DEBUG,
]);
$this->assertSame($expectedVerbosityLevels, $definition->getArgument(2));

$this->assertSame([
'format' => "[%%datetime%%] %%start_tag%%%%level_name%%%%end_tag%% %%message%%\n",
Expand All @@ -209,6 +217,31 @@ public function testArgumentsAreReplacedAsExpected(): void
$this->assertSame('monolog.logger.foo_channel', (string) $argument);
}

public function testConsoleHandlerCanBeInstantiated(): void
{
$container = new ContainerBuilder();
$container->setParameter('kernel.logs_dir', '/var/log');
$container->registerExtension(new MonologExtension());
$container->registerExtension($loggableCommandExtension = new BizkitLoggableCommandExtension());

$loggableCommandExtension->load([[
'channel_name' => 'foo_channel',
'console_handler_options' => [
'bubble' => false,
'stderr_threshold' => 'CRITICAL',
'verbosity_levels' => [
'VERBOSITY_NORMAL' => 'INFO',
'VERBOSITY_VERBOSE' => 'INFO',
],
],
]], $container);

$container->getDefinition(ConsoleHandler::class)->setPublic(true);
$container->compile();

$this->assertInstanceOf(ConsoleHandler::class, $container->get(ConsoleHandler::class));
}

public function testAutoconfigurationIsRegistered(): void
{
$container = new ContainerBuilder();
Expand Down
24 changes: 20 additions & 4 deletions tests/DependencyInjection/Fixtures/DummyFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,29 @@
namespace Bizkit\LoggableCommandBundle\Tests\DependencyInjection\Fixtures;

use Monolog\Formatter\FormatterInterface;
use Monolog\LogRecord;

final class DummyFormatter implements FormatterInterface
{
public function format(array $record)
if (class_exists(LogRecord::class)) {
trait CompatibilityFormatterTrait
{
return null;
public function format(LogRecord $record)
{
return null;
}
}
} else {
trait CompatibilityFormatterTrait
{
public function format(array $record)
{
return null;
}
}
}

final class DummyFormatter implements FormatterInterface
{
use CompatibilityFormatterTrait;

public function formatBatch(array $records)
{
Expand Down

0 comments on commit fa45a83

Please sign in to comment.