From 52b6884e1c43a6b380eb904c28fa25468aecd8f6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 06:14:45 +0000 Subject: [PATCH 01/10] Initial plan From 6e03f2d60618c2c01eee7b061e831393c05054d4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 06:27:35 +0000 Subject: [PATCH 02/10] Add levels parameter to Target constructor and child classes Co-authored-by: samdark <47294+samdark@users.noreply.github.com> --- src/PsrTarget.php | 5 +++-- src/StreamTarget.php | 5 +++-- src/Target.php | 5 ++++- tests/PsrTargetTest.php | 26 ++++++++++++++++++++++++++ tests/StreamTargetTest.php | 17 +++++++++++++++++ tests/TargetTest.php | 31 +++++++++++++++++++++++++++++++ tests/TestAsset/DummyTarget.php | 4 ++-- 7 files changed, 86 insertions(+), 7 deletions(-) diff --git a/src/PsrTarget.php b/src/PsrTarget.php index 486aff1eb..08df8697e 100644 --- a/src/PsrTarget.php +++ b/src/PsrTarget.php @@ -15,10 +15,11 @@ final class PsrTarget extends Target * Sets the PSR-3 logger used to save messages of this target. * * @param LoggerInterface $logger The logger instance to be used for messages processing. + * @param string[] $levels The log message levels that this target is interested in. */ - public function __construct(private LoggerInterface $logger) + public function __construct(private LoggerInterface $logger, array $levels = []) { - parent::__construct(); + parent::__construct($levels); } /** diff --git a/src/StreamTarget.php b/src/StreamTarget.php index e9fd8c058..813141b5b 100644 --- a/src/StreamTarget.php +++ b/src/StreamTarget.php @@ -27,10 +27,11 @@ final class StreamTarget extends Target { /** * @param resource|string $stream A string stream identifier or a stream resource. + * @param string[] $levels The log message levels that this target is interested in. */ - public function __construct(private $stream = 'php://stdout') + public function __construct(private $stream = 'php://stdout', array $levels = []) { - parent::__construct(); + parent::__construct($levels); } protected function export(): void diff --git a/src/Target.php b/src/Target.php index 0ecca2f23..468e48d84 100644 --- a/src/Target.php +++ b/src/Target.php @@ -81,11 +81,14 @@ abstract protected function export(): void; /** * When defining a constructor in child classes, you must call `parent::__construct()`. + * + * @param string[] $levels The log message levels that this target is interested in. */ - public function __construct() + public function __construct(array $levels = []) { $this->categories = new CategoryFilter(); $this->formatter = new Formatter(); + $this->setLevels($levels); } /** diff --git a/tests/PsrTargetTest.php b/tests/PsrTargetTest.php index 490114cc4..5bd84d360 100644 --- a/tests/PsrTargetTest.php +++ b/tests/PsrTargetTest.php @@ -56,4 +56,30 @@ public function testPsrLogInterfaceMethods(string $level, string $message, array $this->target->collect([new Message($level, $message, $context)], true); $this->expectOutputString("{$level}: {$message}: " . json_encode($context, JSON_THROW_ON_ERROR)); } + + public function testSetLevelsViaConstructor(): void + { + $target = new PsrTarget( + new class () implements LoggerInterface { + use LoggerTrait; + + public function log($level, $message, array $context = []): void + { + echo "{$level}: {$message}"; + } + }, + [LogLevel::ERROR, LogLevel::INFO] + ); + + $target->collect( + [ + new Message(LogLevel::INFO, 'message-1', ['foo' => 'bar']), + new Message(LogLevel::DEBUG, 'message-2', ['foo' => true]), + new Message(LogLevel::ERROR, 'message-3', ['foo' => 1]), + ], + true + ); + + $this->expectOutputString("info: message-1error: message-3"); + } } diff --git a/tests/StreamTargetTest.php b/tests/StreamTargetTest.php index 7281704b8..239f861a4 100644 --- a/tests/StreamTargetTest.php +++ b/tests/StreamTargetTest.php @@ -100,4 +100,21 @@ private function exportStreamTarget(StreamTarget $target): void true ); } + + public function testSetLevelsViaConstructor(): void + { + $target = new StreamTarget('php://output', [LogLevel::ERROR, LogLevel::INFO]); + $target->setFormat(static fn (Message $message) => "[{$message->level()}] {$message->message()}"); + + $target->collect( + [ + new Message(LogLevel::INFO, 'message-1', ['foo' => 'bar']), + new Message(LogLevel::DEBUG, 'message-2', ['foo' => true]), + new Message(LogLevel::ERROR, 'message-3', ['foo' => 1]), + ], + true + ); + + $this->expectOutputString("[info] message-1\n[error] message-3\n"); + } } diff --git a/tests/TargetTest.php b/tests/TargetTest.php index 50dfa3fa2..b7465238c 100644 --- a/tests/TargetTest.php +++ b/tests/TargetTest.php @@ -461,6 +461,37 @@ public function testFormatMessageThrowExceptionForPrefixCallableReturnNotBoolean $this->target->formatMessages(); } + public function testSetLevelsViaConstructor(): void + { + $target = new DummyTarget([LogLevel::ERROR, LogLevel::WARNING]); + $logger = new Logger([DummyTarget::class => $target]); + + $logger->setFlushInterval(1); + $logger->log(LogLevel::INFO, 'testInfo'); + $logger->log(LogLevel::ERROR, 'testError'); + $logger->log(LogLevel::WARNING, 'testWarning'); + $logger->log(LogLevel::DEBUG, 'testDebug'); + + $messages = $target->getMessages(); + $this->assertCount(2, $messages); + $this->assertSame('testError', $messages[0]->message()); + $this->assertSame('testWarning', $messages[1]->message()); + } + + public function testSetLevelsViaConstructorWithEmptyArray(): void + { + $target = new DummyTarget([]); + $logger = new Logger([DummyTarget::class => $target]); + + $logger->setFlushInterval(1); + $logger->log(LogLevel::INFO, 'testInfo'); + $logger->log(LogLevel::ERROR, 'testError'); + $logger->log(LogLevel::DEBUG, 'testDebug'); + + $messages = $target->getMessages(); + $this->assertCount(3, $messages); + } + private function collectOneAndExport(string $level, string $message, array $context = []): void { $this->target->collect([new Message($level, $message, $context)], true); diff --git a/tests/TestAsset/DummyTarget.php b/tests/TestAsset/DummyTarget.php index 8de65e9d7..f311831ff 100644 --- a/tests/TestAsset/DummyTarget.php +++ b/tests/TestAsset/DummyTarget.php @@ -14,9 +14,9 @@ final class DummyTarget extends Target private array $exportMessages = []; private Formatter $exportFormatter; - public function __construct() + public function __construct(array $levels = []) { - parent::__construct(); + parent::__construct($levels); $this->exportFormatter = new Formatter(); } From d524b5f4c4706b0fb6787ecc29db34872dcae2aa Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Fri, 5 Dec 2025 06:27:43 +0000 Subject: [PATCH 03/10] Apply fixes from StyleCI --- tests/PsrTargetTest.php | 2 +- tests/StreamTargetTest.php | 4 ++-- tests/TargetTest.php | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/PsrTargetTest.php b/tests/PsrTargetTest.php index 5bd84d360..f35e16572 100644 --- a/tests/PsrTargetTest.php +++ b/tests/PsrTargetTest.php @@ -80,6 +80,6 @@ public function log($level, $message, array $context = []): void true ); - $this->expectOutputString("info: message-1error: message-3"); + $this->expectOutputString('info: message-1error: message-3'); } } diff --git a/tests/StreamTargetTest.php b/tests/StreamTargetTest.php index 239f861a4..916aeb757 100644 --- a/tests/StreamTargetTest.php +++ b/tests/StreamTargetTest.php @@ -105,7 +105,7 @@ public function testSetLevelsViaConstructor(): void { $target = new StreamTarget('php://output', [LogLevel::ERROR, LogLevel::INFO]); $target->setFormat(static fn (Message $message) => "[{$message->level()}] {$message->message()}"); - + $target->collect( [ new Message(LogLevel::INFO, 'message-1', ['foo' => 'bar']), @@ -114,7 +114,7 @@ public function testSetLevelsViaConstructor(): void ], true ); - + $this->expectOutputString("[info] message-1\n[error] message-3\n"); } } diff --git a/tests/TargetTest.php b/tests/TargetTest.php index b7465238c..71d557c4a 100644 --- a/tests/TargetTest.php +++ b/tests/TargetTest.php @@ -465,13 +465,13 @@ public function testSetLevelsViaConstructor(): void { $target = new DummyTarget([LogLevel::ERROR, LogLevel::WARNING]); $logger = new Logger([DummyTarget::class => $target]); - + $logger->setFlushInterval(1); $logger->log(LogLevel::INFO, 'testInfo'); $logger->log(LogLevel::ERROR, 'testError'); $logger->log(LogLevel::WARNING, 'testWarning'); $logger->log(LogLevel::DEBUG, 'testDebug'); - + $messages = $target->getMessages(); $this->assertCount(2, $messages); $this->assertSame('testError', $messages[0]->message()); @@ -482,12 +482,12 @@ public function testSetLevelsViaConstructorWithEmptyArray(): void { $target = new DummyTarget([]); $logger = new Logger([DummyTarget::class => $target]); - + $logger->setFlushInterval(1); $logger->log(LogLevel::INFO, 'testInfo'); $logger->log(LogLevel::ERROR, 'testError'); $logger->log(LogLevel::DEBUG, 'testDebug'); - + $messages = $target->getMessages(); $this->assertCount(3, $messages); } From 17be2bf06f811f6be9e3d743843ad6158b3b74ee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 6 Dec 2025 17:41:56 +0000 Subject: [PATCH 04/10] Add changelog entry for levels constructor parameter Co-authored-by: samdark <47294+samdark@users.noreply.github.com> --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5852fe0e0..4c58aa628 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 2.1.2 under development +- New: Add optional `$levels` parameter to `Target` constructor allowing log level filtering at instantiation (@copilot) - Chg #126: Add `ext-psr` to `conflict` section in `composer.json` (@samdark) ## 2.1.1 June 03, 2025 From cf14a7691e4785cac0eeb1e19fc0442463c1aa9b Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sun, 7 Dec 2025 10:38:04 +0300 Subject: [PATCH 05/10] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c58aa628..fe83d39a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 2.1.2 under development -- New: Add optional `$levels` parameter to `Target` constructor allowing log level filtering at instantiation (@copilot) +- New #128: Add optional `$levels` parameter to `Target` constructor allowing log level filtering at instantiation (@samdark) - Chg #126: Add `ext-psr` to `conflict` section in `composer.json` (@samdark) ## 2.1.1 June 03, 2025 From e936aa649606c5397d87934f548dd2e88ffe49e3 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 9 Dec 2025 20:19:21 +0300 Subject: [PATCH 06/10] Minor corrections --- src/PsrTarget.php | 2 +- src/StreamTarget.php | 2 +- src/Target.php | 4 ++-- tests/PsrTargetTest.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/PsrTarget.php b/src/PsrTarget.php index 08df8697e..36228535a 100644 --- a/src/PsrTarget.php +++ b/src/PsrTarget.php @@ -15,7 +15,7 @@ final class PsrTarget extends Target * Sets the PSR-3 logger used to save messages of this target. * * @param LoggerInterface $logger The logger instance to be used for messages processing. - * @param string[] $levels The log message levels that this target is interested in. + * @param string[] $levels The {@see \Psr\Log\LogLevel log message levels} that this target is interested in. */ public function __construct(private LoggerInterface $logger, array $levels = []) { diff --git a/src/StreamTarget.php b/src/StreamTarget.php index 813141b5b..677ddb78d 100644 --- a/src/StreamTarget.php +++ b/src/StreamTarget.php @@ -27,7 +27,7 @@ final class StreamTarget extends Target { /** * @param resource|string $stream A string stream identifier or a stream resource. - * @param string[] $levels The log message levels that this target is interested in. + * @param string[] $levels The {@see \Psr\Log\LogLevel log message levels} that this target is interested in. */ public function __construct(private $stream = 'php://stdout', array $levels = []) { diff --git a/src/Target.php b/src/Target.php index 468e48d84..cea398096 100644 --- a/src/Target.php +++ b/src/Target.php @@ -82,7 +82,7 @@ abstract protected function export(): void; /** * When defining a constructor in child classes, you must call `parent::__construct()`. * - * @param string[] $levels The log message levels that this target is interested in. + * @param string[] $levels The {@see \Psr\Log\LogLevel log message levels} that this target is interested in. */ public function __construct(array $levels = []) { @@ -150,7 +150,7 @@ public function setExcept(array $except): self } /** - * Sets a list of log message levels that current target is interested in. + * Sets a list of {@see \Psr\Log\LogLevel log message levels} that current target is interested in. * * @param string[] $levels The list of log message levels. * diff --git a/tests/PsrTargetTest.php b/tests/PsrTargetTest.php index f35e16572..69664bb56 100644 --- a/tests/PsrTargetTest.php +++ b/tests/PsrTargetTest.php @@ -65,7 +65,7 @@ public function testSetLevelsViaConstructor(): void public function log($level, $message, array $context = []): void { - echo "{$level}: {$message}"; + echo "$level: $message"; } }, [LogLevel::ERROR, LogLevel::INFO] From ecc4d366f8ee9549afbf3fc755dd70f92e8d49da Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 9 Dec 2025 20:20:22 +0300 Subject: [PATCH 07/10] Fix CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe83d39a1..3633a9503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ - New #104: Add new static methods `Logger::assertLevelIsValid()`, `Logger::assertLevelIsString()` and `Logger::assertLevelIsSupported()` (@vjik) -- New #108: Support of nested values in message templates' variables, e. g. `{foo.bar}` (@vjik) +- New #108: Support of nested values in message templates' variables, e.g. `{foo.bar}` (@vjik) - New #109, #113, #116: Add context providers (@vjik) - New #111: Add `DateTime` and `DateTimeImmutable` support as time in log context (@vjik) - New #112: Add `Message::category()` method and `Message::DEFAULT_CATEGORY` constant, deprecate From fc237829a15a63c8ae9453f6b2290eddc5a2d67a Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 9 Dec 2025 20:32:04 +0300 Subject: [PATCH 08/10] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3633a9503..364d22ff1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 2.1.2 under development -- New #128: Add optional `$levels` parameter to `Target` constructor allowing log level filtering at instantiation (@samdark) +- New #125: Add optional `$levels` parameter to `Target` constructor allowing log level filtering at instantiation (@samdark) - Chg #126: Add `ext-psr` to `conflict` section in `composer.json` (@samdark) ## 2.1.1 June 03, 2025 From 12c9051afb7275b7cd3ccf72caf02b9bef7c8b94 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Wed, 10 Dec 2025 12:08:26 +0300 Subject: [PATCH 09/10] Update tests/TargetTest.php Co-authored-by: Sergei Predvoditelev --- tests/TargetTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TargetTest.php b/tests/TargetTest.php index 71d557c4a..036f321de 100644 --- a/tests/TargetTest.php +++ b/tests/TargetTest.php @@ -481,7 +481,7 @@ public function testSetLevelsViaConstructor(): void public function testSetLevelsViaConstructorWithEmptyArray(): void { $target = new DummyTarget([]); - $logger = new Logger([DummyTarget::class => $target]); + $logger = new Logger([$target]); $logger->setFlushInterval(1); $logger->log(LogLevel::INFO, 'testInfo'); From 42b3c8adeef804dcceb5c72c6cb35cf489ae04ae Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Wed, 10 Dec 2025 12:08:35 +0300 Subject: [PATCH 10/10] Update tests/TargetTest.php Co-authored-by: Sergei Predvoditelev --- tests/TargetTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TargetTest.php b/tests/TargetTest.php index 036f321de..9612390d6 100644 --- a/tests/TargetTest.php +++ b/tests/TargetTest.php @@ -464,7 +464,7 @@ public function testFormatMessageThrowExceptionForPrefixCallableReturnNotBoolean public function testSetLevelsViaConstructor(): void { $target = new DummyTarget([LogLevel::ERROR, LogLevel::WARNING]); - $logger = new Logger([DummyTarget::class => $target]); + $logger = new Logger([$target]); $logger->setFlushInterval(1); $logger->log(LogLevel::INFO, 'testInfo');