From 1387e02612584ffa1a9e93384d2d63ba0a747e11 Mon Sep 17 00:00:00 2001 From: Rod Elias Date: Fri, 14 Oct 2022 12:01:04 -0300 Subject: [PATCH 1/6] Add .editorconfig file (#1768) See: https://editorconfig.org/ --- .editorconfig | 12 ++++++++++++ .gitattributes | 1 + 2 files changed, 13 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..9007f6ba --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/.gitattributes b/.gitattributes index 6da920e3..15891ca2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,3 +5,4 @@ /phpunit.xml.dist export-ignore /_config.yml export-ignore /UPGRADE.md +/.editorconfig export-ignore From e937256eeeed65da2673bbd33a2f02228affbe7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Sat, 4 Feb 2023 11:38:57 -0300 Subject: [PATCH 2/6] Fix date/time field for GCP logging (#1758) We introduced the formatter using the incorrect field, which was making GCP not to extract the correct value from the payload. This uses the field that actually maps to the expected format. More info: https://cloud.google.com/logging/docs/structured-logging --- src/Monolog/Formatter/GoogleCloudLoggingFormatter.php | 3 ++- tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php b/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php index 0cd287f5..ca52ebf4 100644 --- a/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php +++ b/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php @@ -17,6 +17,7 @@ use Monolog\LogRecord; /** * Encodes message information into JSON in a format compatible with Cloud logging. * + * @see https://cloud.google.com/logging/docs/structured-logging * @see https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry * * @author Luís Cobucci @@ -28,7 +29,7 @@ final class GoogleCloudLoggingFormatter extends JsonFormatter { // Re-key level for GCP logging $record['severity'] = $record['level_name']; - $record['timestamp'] = $record['datetime']->format(DateTimeInterface::RFC3339_EXTENDED); + $record['time'] = $record['datetime']->format(DateTimeInterface::RFC3339_EXTENDED); // Remove keys that are not used by GCP unset($record['level'], $record['level_name'], $record['datetime']); diff --git a/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php b/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php index 27aea2ca..55dfc76d 100644 --- a/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php +++ b/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php @@ -30,8 +30,8 @@ class GoogleCloudLoggingFormatterTest extends TestCase $formatted_decoded = json_decode($formatter->format($record), true); $this->assertArrayNotHasKey("datetime", $formatted_decoded); - $this->assertArrayHasKey("timestamp", $formatted_decoded); - $this->assertSame($record['datetime']->format(DateTimeInterface::RFC3339_EXTENDED), $formatted_decoded["timestamp"]); + $this->assertArrayHasKey("time", $formatted_decoded); + $this->assertSame($record['datetime']->format(DateTimeInterface::RFC3339_EXTENDED), $formatted_decoded["time"]); } /** From 58f503004d3ed587ea1a0395382e336015378b6e Mon Sep 17 00:00:00 2001 From: Mikhail Popov Date: Sat, 4 Feb 2023 17:46:32 +0300 Subject: [PATCH 3/6] Fix setting of extra attributes in AmqpHandler when handling batches of records (#1781) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One of content_type, content_encoding, message_id, user_id, app_id, delivery_mode, priority, timestamp, expiration, type or reply_to, headers. Co-authored-by: Попов Михаил --- src/Monolog/Handler/AmqpHandler.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index c4997482..994872ce 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -151,13 +151,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 ($this->extraAttributes) { + $attributes = array_merge($attributes, $this->extraAttributes); + } + return new AMQPMessage($data, $attributes); } /** From 0f014206a44e9b095b93a69c64187733366c1aa3 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Sat, 4 Feb 2023 15:49:17 +0100 Subject: [PATCH 4/6] Fix cycle detection within fibers (#1753) * Fix cycle detection within fibers We keep a separate depth count per fiber. Fixes #1752. * Avoid additional call to Fiber::getCurrent() Suppresses phpstan errors, as they're false positives. --- src/Monolog/Logger.php | 34 ++++++++++++++-- tests/Monolog/LoggerTest.php | 76 ++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 1ab75b9e..f9ec27e8 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -168,6 +168,11 @@ class Logger implements LoggerInterface, ResettableInterface */ private $logDepth = 0; + /** + * @var \WeakMap<\Fiber, int>|null Keeps track of depth inside fibers to prevent infinite logging loops + */ + private $fiberLogDepth; + /** * @var bool Whether to detect infinite logging loops * @@ -189,6 +194,13 @@ class Logger implements LoggerInterface, ResettableInterface $this->setHandlers($handlers); $this->processors = $processors; $this->timezone = $timezone ?: new DateTimeZone(date_default_timezone_get() ?: 'UTC'); + + if (\PHP_VERSION_ID >= 80100) { + // Local variable for phpstan, see https://github.com/phpstan/phpstan/issues/6732#issuecomment-1111118412 + /** @var \WeakMap<\Fiber, int> $fiberLogDepth */ + $fiberLogDepth = new \WeakMap(); + $this->fiberLogDepth = $fiberLogDepth; + } } public function getName(): string @@ -332,12 +344,21 @@ class Logger implements LoggerInterface, ResettableInterface } if ($this->detectCycles) { - $this->logDepth += 1; + // @phpstan-ignore-next-line + if (\PHP_VERSION_ID >= 80100 && $fiber = \Fiber::getCurrent()) { + $this->fiberLogDepth[$fiber] = $this->fiberLogDepth[$fiber] ?? 0; + $logDepth = ++$this->fiberLogDepth[$fiber]; + } 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; } @@ -387,7 +408,12 @@ class Logger implements LoggerInterface, ResettableInterface } } finally { if ($this->detectCycles) { - $this->logDepth--; + if (isset($fiber)) { + // @phpstan-ignore-next-line + $this->fiberLogDepth[$fiber]--; + } else { + $this->logDepth--; + } } } diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index fd99df20..a0ec7405 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -792,6 +792,58 @@ class LoggerTest extends \PHPUnit\Framework\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 @@ -826,3 +878,27 @@ class LoggingHandler implements HandlerInterface { } } + + +class FiberSuspendHandler implements HandlerInterface +{ + public function isHandling(array $record): bool + { + return true; + } + + public function handle(array $record): bool + { + \Fiber::suspend(); + + return true; + } + + public function handleBatch(array $records): void + { + } + + public function close(): void + { + } +} \ No newline at end of file From 6459aeb4a7adf2c10ab7210743f42af872f27d0b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 4 Feb 2023 15:53:31 +0100 Subject: [PATCH 5/6] Fix ignores --- phpstan.neon.dist | 4 ++++ src/Monolog/Logger.php | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index eb126d4a..81d47e3e 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -44,3 +44,7 @@ parameters: # legacy GelfPHP 1.x failures - '# Gelf\\Message::set(Facility|Line|File)\(#' + + # php 8.1 Fiber failures + - '#unknown class Fiber#' + - '#Offset mixed does not exist on WeakMap\|null\.#' diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index f9ec27e8..775d7cf1 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -344,7 +344,6 @@ class Logger implements LoggerInterface, ResettableInterface } if ($this->detectCycles) { - // @phpstan-ignore-next-line if (\PHP_VERSION_ID >= 80100 && $fiber = \Fiber::getCurrent()) { $this->fiberLogDepth[$fiber] = $this->fiberLogDepth[$fiber] ?? 0; $logDepth = ++$this->fiberLogDepth[$fiber]; @@ -409,7 +408,6 @@ class Logger implements LoggerInterface, ResettableInterface } finally { if ($this->detectCycles) { if (isset($fiber)) { - // @phpstan-ignore-next-line $this->fiberLogDepth[$fiber]--; } else { $this->logDepth--; From 8255feb4446728566db3bf537574d18bdf850472 Mon Sep 17 00:00:00 2001 From: Bart Swaalf Date: Tue, 15 Nov 2022 11:32:46 +0100 Subject: [PATCH 6/6] Add support for enum context values to psr formatter (#1773) --- src/Monolog/Processor/PsrLogMessageProcessor.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 2c2a00e7..e7c12176 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -66,6 +66,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)) {