mirror of
https://github.com/Seldaek/monolog.git
synced 2025-10-23 17:46:09 +02:00
Fix infinite loops when a log handler triggers logging itself
This commit is contained in:
@@ -147,6 +147,11 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
*/
|
||||
protected $exceptionHandler;
|
||||
|
||||
/**
|
||||
* @var int Keeps track of depth to prevent infinite logging loops
|
||||
*/
|
||||
private $logDepth = 0;
|
||||
|
||||
/**
|
||||
* @psalm-param array<callable(array): array> $processors
|
||||
*
|
||||
@@ -291,30 +296,51 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
*/
|
||||
public function addRecord(int $level, string $message, array $context = []): bool
|
||||
{
|
||||
$record = null;
|
||||
$this->logDepth += 1;
|
||||
if ($this->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
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->handlers as $handler) {
|
||||
if (null === $record) {
|
||||
// skip creating the record as long as no handler is going to handle it
|
||||
if (!$handler->isHandling(['level' => $level])) {
|
||||
continue;
|
||||
try {
|
||||
$record = null;
|
||||
|
||||
foreach ($this->handlers as $handler) {
|
||||
if (null === $record) {
|
||||
// skip creating the record as long as no handler is going to handle it
|
||||
if (!$handler->isHandling(['level' => $level])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$levelName = static::getLevelName($level);
|
||||
|
||||
$record = [
|
||||
'message' => $message,
|
||||
'context' => $context,
|
||||
'level' => $level,
|
||||
'level_name' => $levelName,
|
||||
'channel' => $this->name,
|
||||
'datetime' => new DateTimeImmutable($this->microsecondTimestamps, $this->timezone),
|
||||
'extra' => [],
|
||||
];
|
||||
|
||||
try {
|
||||
foreach ($this->processors as $processor) {
|
||||
$record = $processor($record);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$this->handleException($e, $record);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$levelName = static::getLevelName($level);
|
||||
|
||||
$record = [
|
||||
'message' => $message,
|
||||
'context' => $context,
|
||||
'level' => $level,
|
||||
'level_name' => $levelName,
|
||||
'channel' => $this->name,
|
||||
'datetime' => new DateTimeImmutable($this->microsecondTimestamps, $this->timezone),
|
||||
'extra' => [],
|
||||
];
|
||||
|
||||
// once the record exists, send it to all handlers as long as the bubbling chain is not interrupted
|
||||
try {
|
||||
foreach ($this->processors as $processor) {
|
||||
$record = $processor($record);
|
||||
if (true === $handler->handle($record)) {
|
||||
break;
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$this->handleException($e, $record);
|
||||
@@ -322,17 +348,8 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// once the record exists, send it to all handlers as long as the bubbling chain is not interrupted
|
||||
try {
|
||||
if (true === $handler->handle($record)) {
|
||||
break;
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$this->handleException($e, $record);
|
||||
|
||||
return true;
|
||||
}
|
||||
} finally {
|
||||
$this->logDepth--;
|
||||
}
|
||||
|
||||
return null !== $record;
|
||||
|
Reference in New Issue
Block a user