1
0
mirror of https://github.com/Seldaek/monolog.git synced 2025-08-05 12:47:39 +02:00

Merge branch '2.x'

This commit is contained in:
Jordi Boggiano
2023-02-04 16:23:13 +01:00
10 changed files with 138 additions and 31 deletions

12
.editorconfig Normal file
View File

@@ -0,0 +1,12 @@
root = true
[*]
charset = utf-8
indent_size = 4
indent_style = space
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.{yml,yaml}]
indent_size = 2

1
.gitattributes vendored
View File

@@ -5,3 +5,4 @@
/phpunit.xml.dist export-ignore
/_config.yml export-ignore
/UPGRADE.md export-ignore
/.editorconfig export-ignore

View File

@@ -10,11 +10,6 @@ parameters:
count: 1
path: src/Monolog/Formatter/JsonFormatter.php
-
message: "#^Cannot access offset 'table' on array\\<array\\|bool\\|float\\|int\\|string\\|null\\>\\|bool\\|float\\|int\\|object\\|string\\.$#"
count: 1
path: src/Monolog/Formatter/WildfireFormatter.php
-
message: "#^Return type \\(array\\<array\\|bool\\|float\\|int\\|string\\|null\\>\\|bool\\|float\\|int\\|object\\|string\\|null\\) of method Monolog\\\\Formatter\\\\WildfireFormatter\\:\\:normalize\\(\\) should be covariant with return type \\(array\\<array\\|bool\\|float\\|int\\|string\\|null\\>\\|bool\\|float\\|int\\|string\\|null\\) of method Monolog\\\\Formatter\\\\NormalizerFormatter\\:\\:normalize\\(\\)$#"
count: 1
@@ -80,16 +75,21 @@ parameters:
count: 1
path: src/Monolog/Handler/SamplingHandler.php
-
message: "#^Match expression does not handle remaining value\\: 'EMERGENCY'$#"
count: 1
path: src/Monolog/Level.php
-
message: "#^Variable property access on \\$this\\(Monolog\\\\LogRecord\\)\\.$#"
count: 4
path: src/Monolog/LogRecord.php
-
message: "#^Cannot assign offset Fiber to WeakMap\\<Fiber\\<mixed, mixed, mixed, mixed\\>, int\\>\\.$#"
count: 1
path: src/Monolog/Logger.php
-
message: "#^Only numeric types are allowed in post\\-decrement, int\\|null given\\.$#"
count: 1
path: src/Monolog/Logger.php
-
message: "#^Parameter \\#1 \\$level \\('alert'\\|'critical'\\|'debug'\\|'emergency'\\|'error'\\|'info'\\|'notice'\\|'warning'\\|Monolog\\\\Level\\) of method Monolog\\\\Logger\\:\\:log\\(\\) should be contravariant with parameter \\$level \\(mixed\\) of method Psr\\\\Log\\\\LoggerInterface\\:\\:log\\(\\)$#"
count: 1
@@ -105,11 +105,6 @@ parameters:
count: 1
path: src/Monolog/Processor/UidProcessor.php
-
message: "#^Method Monolog\\\\Processor\\\\UidProcessor\\:\\:generateUid\\(\\) should return non\\-empty\\-string but returns string\\.$#"
count: 1
path: src/Monolog/Processor/UidProcessor.php
-
message: "#^Parameter \\#1 \\$length of function random_bytes expects int\\<1, max\\>, int given\\.$#"
count: 1
@@ -119,4 +114,3 @@ parameters:
message: "#^Parameter \\#2 \\$callback of function preg_replace_callback expects callable\\(array\\<int\\|string, string\\>\\)\\: string, Closure\\(mixed\\)\\: array\\<int, string\\>\\|string\\|false given\\.$#"
count: 1
path: src/Monolog/Utils.php

View File

@@ -139,13 +139,14 @@ class AmqpHandler extends AbstractProcessingHandler
private function createAmqpMessage(string $data): AMQPMessage
{
return new AMQPMessage(
$data,
[
'delivery_mode' => 2,
'content_type' => 'application/json',
]
);
$attributes = [
'delivery_mode' => 2,
'content_type' => 'application/json',
];
if (\count($this->extraAttributes) > 0) {
$attributes = array_merge($attributes, $this->extraAttributes);
}
return new AMQPMessage($data, $attributes);
}
/**

View File

@@ -170,7 +170,7 @@ class RotatingFileHandler extends StreamHandler
$timedFilename = str_replace(
['{filename}', '{date}'],
[$fileInfo['filename'], date($this->dateFormat)],
$fileInfo['dirname'] . '/' . $this->filenameFormat
($fileInfo['dirname'] ?? '') . '/' . $this->filenameFormat
);
if (isset($fileInfo['extension'])) {
@@ -190,7 +190,7 @@ class RotatingFileHandler extends StreamHandler
['[0-9][0-9][0-9][0-9]', '[0-9][0-9]', '[0-9][0-9]', '[0-9][0-9]'],
$this->dateFormat)
],
$fileInfo['dirname'] . '/' . $this->filenameFormat
($fileInfo['dirname'] ?? '') . '/' . $this->filenameFormat
);
if (isset($fileInfo['extension'])) {
$glob .= '.'.$fileInfo['extension'];

View File

@@ -13,6 +13,7 @@ namespace Monolog;
use Closure;
use DateTimeZone;
use Fiber;
use Monolog\Handler\HandlerInterface;
use Monolog\Processor\ProcessorInterface;
use Psr\Log\LoggerInterface;
@@ -20,6 +21,7 @@ use Psr\Log\InvalidArgumentException;
use Psr\Log\LogLevel;
use Throwable;
use Stringable;
use WeakMap;
/**
* Monolog log channel
@@ -151,9 +153,13 @@ class Logger implements LoggerInterface, ResettableInterface
*/
private int $logDepth = 0;
/**
* @var WeakMap<Fiber<mixed, mixed, mixed, mixed>, int> Keeps track of depth inside fibers to prevent infinite logging loops
*/
private WeakMap $fiberLogDepth;
/**
* Whether to detect infinite logging loops
*
* This can be disabled via {@see useLoggingLoopDetection} if you have async handlers that do not play well with this
*/
private bool $detectCycles = true;
@@ -172,6 +178,7 @@ class Logger implements LoggerInterface, ResettableInterface
$this->setHandlers($handlers);
$this->processors = $processors;
$this->timezone = $timezone ?? new DateTimeZone(date_default_timezone_get());
$this->fiberLogDepth = new \WeakMap();
}
public function getName(): string
@@ -318,12 +325,19 @@ class Logger implements LoggerInterface, ResettableInterface
}
if ($this->detectCycles) {
$this->logDepth += 1;
if (null !== ($fiber = Fiber::getCurrent())) {
$logDepth = $this->fiberLogDepth[$fiber] = ($this->fiberLogDepth[$fiber] ?? 0) + 1;
} else {
$logDepth = ++$this->logDepth;
}
} else {
$logDepth = 0;
}
if ($this->logDepth === 3) {
if ($logDepth === 3) {
$this->warning('A possible infinite logging loop was detected and aborted. It appears some of your handler code is triggering logging, see the previous log record for a hint as to what may be the cause.');
return false;
} elseif ($this->logDepth >= 5) { // log depth 4 is let through so we can log the warning above
} elseif ($logDepth >= 5) { // log depth 4 is let through, so we can log the warning above
return false;
}
@@ -375,7 +389,11 @@ class Logger implements LoggerInterface, ResettableInterface
return $handled;
} finally {
if ($this->detectCycles) {
$this->logDepth--;
if (isset($fiber)) {
$this->fiberLogDepth[$fiber]--;
} else {
$this->logDepth--;
}
}
}
}

View File

@@ -67,6 +67,8 @@ class PsrLogMessageProcessor implements ProcessorInterface
} else {
$replacements[$placeholder] = $val->format($this->dateFormat ?? static::SIMPLE_DATE);
}
} elseif ($val instanceof \UnitEnum) {
$replacements[$placeholder] = $val instanceof \BackedEnum ? $val->value : $val->name;
} elseif (is_object($val)) {
$replacements[$placeholder] = '[object '.Utils::getClass($val).']';
} elseif (is_array($val)) {

View File

@@ -73,9 +73,10 @@ class SignalHandler
*/
public function handleSignal(int $signo, $siginfo = null): void
{
/** @var array<int, string> $signals */
static $signals = [];
if (!$signals && extension_loaded('pcntl')) {
if (\count($signals) === 0 && extension_loaded('pcntl')) {
$pcntl = new ReflectionExtension('pcntl');
foreach ($pcntl->getConstants() as $name => $value) {
if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && is_int($value)) {

View File

@@ -793,6 +793,58 @@ class LoggerTest extends TestCase
$this->assertEquals($datetime->format('Y-m-d H:i:s'), $record->datetime->format('Y-m-d H:i:s'));
}
}
/**
* @requires PHP 8.1
*/
public function testLogCycleDetectionWithFibersWithoutCycle()
{
$logger = new Logger(__METHOD__);
$fiberSuspendHandler = new FiberSuspendHandler();
$testHandler = new TestHandler();
$logger->pushHandler($fiberSuspendHandler);
$logger->pushHandler($testHandler);
$fibers = [];
for ($i = 0; $i < 10; $i++) {
$fiber = new \Fiber(static function () use ($logger) {
$logger->info('test');
});
$fiber->start();
// We need to keep a reference here, because otherwise the fiber gets automatically cleaned up
$fibers[] = $fiber;
}
self::assertCount(10, $testHandler->getRecords());
}
/**
* @requires PHP 8.1
*/
public function testLogCycleDetectionWithFibersWithCycle()
{
$logger = new Logger(__METHOD__);
$fiberSuspendHandler = new FiberSuspendHandler();
$loggingHandler = new LoggingHandler($logger);
$testHandler = new TestHandler();
$logger->pushHandler($fiberSuspendHandler);
$logger->pushHandler($loggingHandler);
$logger->pushHandler($testHandler);
$fiber = new \Fiber(static function () use ($logger) {
$logger->info('test');
});
$fiber->start();
self::assertCount(3, $testHandler->getRecords());
}
}
class LoggingHandler implements HandlerInterface
@@ -827,3 +879,27 @@ class LoggingHandler implements HandlerInterface
{
}
}
class FiberSuspendHandler implements HandlerInterface
{
public function isHandling(LogRecord $record): bool
{
return true;
}
public function handle(LogRecord $record): bool
{
\Fiber::suspend();
return true;
}
public function handleBatch(array $records): void
{
}
public function close(): void
{
}
}

View File

@@ -11,6 +11,7 @@
namespace Monolog\Processor;
use Monolog\Level;
use Monolog\Test\TestCase;
class PsrLogMessageProcessorTest extends TestCase
@@ -66,6 +67,7 @@ class PsrLogMessageProcessorTest extends TestCase
[[1, 2, 3], 'array[1,2,3]'],
[['foo' => 'bar'], 'array{"foo":"bar"}'],
[stream_context_create(), '[resource]'],
[Level::Info, Level::Info->value],
];
}
}