diff --git a/CHANGELOG.md b/CHANGELOG.md index c49001678..fe1731f03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - **Other Features** - [spiral/queue] Added `Spiral\Queue\Interceptor\Consume\RetryPolicyInterceptor` to enable automatic job retries with a configurable retry policy. + - [spiral/monolog-bridge] Added the ability to configure the **Monolog** messages format via environment variable + `MONOLOG_FORMAT`. ## 3.8.4 - 2023-09-08 diff --git a/src/Bridge/Monolog/src/Bootloader/MonologBootloader.php b/src/Bridge/Monolog/src/Bootloader/MonologBootloader.php index 76eb30050..6796bc322 100644 --- a/src/Bridge/Monolog/src/Bootloader/MonologBootloader.php +++ b/src/Bridge/Monolog/src/Bootloader/MonologBootloader.php @@ -31,12 +31,15 @@ final class MonologBootloader extends Bootloader implements Container\SingletonI 'log.rotate' => [self::class, 'logRotate'], ]; + private const DEFAULT_FORMAT = "[%datetime%] %level_name%: %message% %context%\n"; + public function __construct( - private readonly ConfiguratorInterface $config + private readonly ConfiguratorInterface $config, + private readonly EnvironmentInterface $env, ) { } - public function init(Container $container, FinalizerInterface $finalizer, EnvironmentInterface $env): void + public function init(Container $container, FinalizerInterface $finalizer): void { $finalizer->addFinalizer(static function (bool $terminate) use ($container): void { if ($terminate) { @@ -61,7 +64,7 @@ public function init(Container $container, FinalizerInterface $finalizer, Enviro }); $this->config->setDefaults(MonologConfig::CONFIG, [ - 'default' => $env->get('MONOLOG_DEFAULT_CHANNEL', MonologConfig::DEFAULT_CHANNEL), + 'default' => $this->env->get('MONOLOG_DEFAULT_CHANNEL', MonologConfig::DEFAULT_CHANNEL), 'globalLevel' => Logger::DEBUG, 'handlers' => [], ]); @@ -101,7 +104,7 @@ public function logRotate( ); return $handler->setFormatter( - new LineFormatter("[%datetime%] %level_name%: %message% %context%\n") + new LineFormatter($this->env->get('MONOLOG_FORMAT', self::DEFAULT_FORMAT)) ); } } diff --git a/src/Bridge/Monolog/tests/Config/MonologConfigTest.php b/src/Bridge/Monolog/tests/Config/MonologConfigTest.php new file mode 100644 index 000000000..a86f5eeb2 --- /dev/null +++ b/src/Bridge/Monolog/tests/Config/MonologConfigTest.php @@ -0,0 +1,68 @@ +assertSame(MonologConfig::DEFAULT_CHANNEL, $config->getDefault()); + + $config = new MonologConfig(['default' => 'foo']); + $this->assertSame('foo', $config->getDefault()); + } + + public function testGetEventLevel(): void + { + $config = new MonologConfig(); + $this->assertSame(Logger::DEBUG, $config->getEventLevel()); + + $config = new MonologConfig(['globalLevel' => Logger::INFO]); + $this->assertSame(Logger::INFO, $config->getEventLevel()); + } + + public function testGetHandlers(): void + { + $config = new MonologConfig(); + $this->assertEmpty(\iterator_to_array($config->getHandlers('foo'))); + + $config = new MonologConfig([ + 'handlers' => [ + 'foo' => [ + $this->createMock(HandlerInterface::class) + ] + ] + ]); + $this->assertInstanceOf( + HandlerInterface::class, + \iterator_to_array($config->getHandlers('foo'))[0] + ); + } + + public function testGetProcessors(): void + { + $config = new MonologConfig(); + $this->assertEmpty(\iterator_to_array($config->getProcessors('foo'))); + + $config = new MonologConfig([ + 'processors' => [ + 'foo' => [ + $this->createMock(ProcessorInterface::class) + ] + ] + ]); + $this->assertInstanceOf( + ProcessorInterface::class, + \iterator_to_array($config->getProcessors('foo'))[0] + ); + } +} diff --git a/src/Bridge/Monolog/tests/RotateHandlerTest.php b/src/Bridge/Monolog/tests/RotateHandlerTest.php index 93414111c..2a5e1d799 100644 --- a/src/Bridge/Monolog/tests/RotateHandlerTest.php +++ b/src/Bridge/Monolog/tests/RotateHandlerTest.php @@ -6,7 +6,13 @@ use Monolog\Handler\RotatingFileHandler; use Monolog\Logger; +use Spiral\Boot\BootloadManager\DefaultInvokerStrategy; +use Spiral\Boot\BootloadManager\Initializer; +use Spiral\Boot\BootloadManager\InitializerInterface; +use Spiral\Boot\BootloadManager\InvokerStrategyInterface; use Spiral\Boot\BootloadManager\StrategyBasedBootloadManager; +use Spiral\Boot\Environment; +use Spiral\Boot\EnvironmentInterface; use Spiral\Boot\FinalizerInterface; use Spiral\Config\ConfigManager; use Spiral\Config\ConfiguratorInterface; @@ -16,6 +22,14 @@ class RotateHandlerTest extends BaseTest { + protected function setUp(): void + { + parent::setUp(); + + $this->container->bind(InvokerStrategyInterface::class, DefaultInvokerStrategy::class); + $this->container->bind(InitializerInterface::class, Initializer::class); + } + public function testRotateHandler(): void { $this->container->bind(FinalizerInterface::class, $finalizer = \Mockery::mock(FinalizerInterface::class)); @@ -46,4 +60,27 @@ public function load(string $section): array $this->assertSame(Logger::DEBUG, $handler->getLevel()); } + + public function testChangeFormat(): void + { + $this->container->bind(FinalizerInterface::class, $finalizer = \Mockery::mock(FinalizerInterface::class)); + $finalizer->shouldReceive('addFinalizer')->once(); + + $this->container->bind(EnvironmentInterface::class, new Environment(['MONOLOG_FORMAT' => 'foo'])); + $this->container->bind(ConfiguratorInterface::class, $this->createMock(ConfiguratorInterface::class)); + $this->container->get(StrategyBasedBootloadManager::class)->bootload([MonologBootloader::class]); + + $autowire = new Container\Autowire('log.rotate', [ + 'filename' => 'monolog.log' + ]); + + /** @var RotatingFileHandler $handler */ + $handler = $autowire->resolve($this->container); + $this->assertInstanceOf(RotatingFileHandler::class, $handler); + + $this->assertSame(Logger::DEBUG, $handler->getLevel()); + + $formatter = $handler->getFormatter(); + $this->assertSame('foo', (new \ReflectionProperty($formatter, 'format'))->getValue($formatter)); + } }