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:
12
.editorconfig
Normal file
12
.editorconfig
Normal 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
1
.gitattributes
vendored
@@ -5,3 +5,4 @@
|
||||
/phpunit.xml.dist export-ignore
|
||||
/_config.yml export-ignore
|
||||
/UPGRADE.md export-ignore
|
||||
/.editorconfig export-ignore
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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'];
|
||||
|
@@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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)) {
|
||||
|
@@ -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)) {
|
||||
|
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@@ -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],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user