Skip to content
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Enh #132: Add benchmarks, improve performance of `Message::parse()` (@samdark)
- Bug #130: Updated `Message::parse()` to correctly support multiple placeholders (@technicated)
- Chg #130, #133: Changed `Message::parse()` to conform to PSR-3 (@technicated, @vjik)
- Enh #135: Add validation for `$traceLevel` in `SystemContextProvider` to ensure values are greater than or equal to zero (@rekmixa)
- Enh #137: Explicitly import classes, functions, and constants in "use" section (@mspirkov)

## 2.2.0 December 13, 2025
Expand Down
5 changes: 4 additions & 1 deletion infection.json.dist
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
}
},
"mutators": {
"@default": true
"@default": true,
"global-ignoreSourceCodeByRegex": [
"register_shutdown_function"
]
}
}
24 changes: 23 additions & 1 deletion src/ContextProvider/SystemContextProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
private int $traceLevel = 0,
array $excludedTracePaths = [],
) {
$this->assertTraceLevelIsValid($this->traceLevel);
/** @psalm-suppress DeprecatedMethod `setExcludedTracePaths` will be private and not deprecated */
$this->setExcludedTracePaths($excludedTracePaths);
}
Expand Down Expand Up @@ -61,7 +62,9 @@
*/
public function setTraceLevel(int $traceLevel): self
{
$this->assertTraceLevelIsValid($traceLevel);

Check warning on line 65 in src/ContextProvider/SystemContextProvider.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "MethodCallRemoval": @@ @@ */ public function setTraceLevel(int $traceLevel): self { - $this->assertTraceLevelIsValid($traceLevel); + $this->traceLevel = $traceLevel; return $this;
$this->traceLevel = $traceLevel;

return $this;
}

Expand Down Expand Up @@ -114,7 +117,7 @@
if (isset($trace['file'], $trace['line'])) {
$excludedMatch = array_filter(
$this->excludedTracePaths,
static fn($path) => str_contains($trace['file'], $path),
static fn(string $path): bool => str_contains($trace['file'], $path),
);

if (empty($excludedMatch)) {
Expand All @@ -129,4 +132,23 @@

return $traces;
}

/**
* Validates $traceLevel property
*
* @param int $traceLevel The number of call stack information.
*
* @see self::$traceLevel
*/
private function assertTraceLevelIsValid(int $traceLevel): void
{
if ($traceLevel < 0) {
throw new InvalidArgumentException(
sprintf(
'Trace level must be greater than or equal to zero, %s received.',
$traceLevel,
),
);
}
}
}
21 changes: 5 additions & 16 deletions src/Logger.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
use RuntimeException;
use Stringable;
use Throwable;
use Yiisoft\Log\ContextProvider\SystemContextProvider;
use Yiisoft\Log\ContextProvider\ContextProviderInterface;
use Yiisoft\Log\ContextProvider\SystemContextProvider;

use function count;
use function implode;
Expand Down Expand Up @@ -88,7 +88,7 @@
$this->setTargets($targets);
$this->contextProvider = $contextProvider ?? new SystemContextProvider();

register_shutdown_function(function () {

Check warning on line 91 in src/Logger.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "FunctionCallRemoval": @@ @@ $this->setTargets($targets); $this->contextProvider = $contextProvider ?? new SystemContextProvider(); - register_shutdown_function(function () { - // make regular flush before other shutdown functions, which allows session data collection and so on - $this->flush(); - // make sure log entries written by shutdown functions are also flushed - // ensure "flush()" is called last when there are multiple shutdown functions - register_shutdown_function([$this, 'flush'], true); - }); + } /**
// make regular flush before other shutdown functions, which allows session data collection and so on
$this->flush();
// make sure log entries written by shutdown functions are also flushed
Expand All @@ -105,24 +105,13 @@
* @throws \Psr\Log\InvalidArgumentException for invalid log message level.
*
* @return string The text display of the level.
* @deprecated since 2.1, to be removed in 3.0. Use {@see LogLevel::assertLevelIsValid()} instead.
* @deprecated since 2.1, to be removed in 3.0. Use {@see Logger::assertLevelIsValid()} instead.
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function validateLevel(mixed $level): string
{
if (!is_string($level)) {
throw new \Psr\Log\InvalidArgumentException(sprintf(
'The log message level must be a string, %s provided.',
get_debug_type($level),
));
}

if (!in_array($level, self::LEVELS, true)) {
throw new \Psr\Log\InvalidArgumentException(sprintf(
'Invalid log message level "%s" provided. The following values are supported: "%s".',
$level,
implode('", "', self::LEVELS),
));
}
self::assertLevelIsValid($level);

return $level;
}
Expand All @@ -145,7 +134,7 @@
array_merge($this->contextProvider->getContext(), $context),
);

if ($this->flushInterval > 0 && count($this->messages) >= $this->flushInterval) {

Check warning on line 137 in src/Logger.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "GreaterThan": @@ @@ array_merge($this->contextProvider->getContext(), $context), ); - if ($this->flushInterval > 0 && count($this->messages) >= $this->flushInterval) { + if ($this->flushInterval >= 0 && count($this->messages) >= $this->flushInterval) { $this->flush(); } }
$this->flush();
}
}
Expand Down Expand Up @@ -242,7 +231,7 @@
*
* @psalm-assert string $level
*/
public static function assertLevelIsString(mixed $level): void

Check warning on line 234 in src/Logger.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "PublicVisibility": @@ @@ * * @psalm-assert string $level */ - public static function assertLevelIsString(mixed $level): void + protected static function assertLevelIsString(mixed $level): void { if (is_string($level)) { return;
{
if (is_string($level)) {
return;
Expand Down
29 changes: 29 additions & 0 deletions tests/ContextProvider/SystemContextProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Log\Tests\ContextProvider;

use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use Yiisoft\Log\ContextProvider\SystemContextProvider;

final class SystemContextProviderTest extends TestCase
{
public function testWrongTraceLevel(): void
{
$this->expectException(InvalidArgumentException::class);
new SystemContextProvider(-1);
}

public function testContextHasNeededData(): void
{
$provider = new SystemContextProvider();
$context = $provider->getContext();

$this->assertArrayHasKey('time', $context);
$this->assertArrayHasKey('trace', $context);
$this->assertArrayHasKey('memory', $context);
$this->assertArrayHasKey('category', $context);
}
}
16 changes: 15 additions & 1 deletion tests/LoggerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,24 @@ public function testLog(): void
$this->assertGreaterThanOrEqual($memory, $messages[1]->context('memory'));
}

public function testLogWithWrongLevel(): void
{
$this->expectException(\Psr\Log\InvalidArgumentException::class);
$this->logger->log(123, 'test1');
}

public function testLogWithUnsupportedLevel(): void
{
$this->expectException(\Psr\Log\InvalidArgumentException::class);
$this->logger->log('unsupported-level', 'test1');
}

public function testLogWithTraceLevel(): void
{
$memory = memory_get_usage();
$this->logger->setTraceLevel($traceLevel = 3);

$line = __LINE__;
$this->logger->log(LogLevel::INFO, 'test3');
$messages = $this->getInaccessibleMessages($this->logger);

Expand All @@ -70,7 +83,7 @@ public function testLogWithTraceLevel(): void
$this->assertSame('application', $messages[0]->context('category'));
$this->assertSame([
'file' => __FILE__,
'line' => 64,
'line' => $line + 1,
'function' => 'log',
'class' => Logger::class,
'type' => '->',
Expand Down Expand Up @@ -145,6 +158,7 @@ public function testSetExcludedTracePaths(): void
$this->logger->info('info message');
$messages = $this->getInaccessibleMessages($this->logger);

$this->assertNotEmpty($messages[1]->context('trace'));
foreach ($messages[1]->context('trace') as $trace) {
$this->assertNotSame(__FILE__, $trace['file']);
}
Expand Down
Loading