Quellcode durchsuchen

Merge branch '2.x'

Jordi Boggiano vor 3 Jahren
Ursprung
Commit
7d31b642bd

+ 5 - 1
src/Monolog/Formatter/LineFormatter.php

@@ -182,7 +182,11 @@ class LineFormatter extends NormalizerFormatter
     {
         if ($this->allowInlineLineBreaks) {
             if (0 === strpos($str, '{')) {
-                return str_replace(['\r', '\n'], ["\r", "\n"], $str);
+                $str = preg_replace('/(?<!\\\\)\\\\[rn]/', "\n", $str);
+                if (null === $str) {
+                    $pcreErrorCode = preg_last_error();
+                    throw new \RuntimeException('Failed to run preg_replace: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode));
+                }
             }
 
             return $str;

+ 32 - 6
src/Monolog/Logger.php

@@ -106,6 +106,22 @@ class Logger implements LoggerInterface, ResettableInterface
      */
     public const API = 3;
 
+    /**
+     * Mapping between levels numbers defined in RFC 5424 and Monolog ones
+     *
+     * @phpstan-var array<int, Level> $rfc_5424_levels
+     */
+    private const RFC_5424_LEVELS = [
+        7 => Level::Debug,
+        6 => Level::Info,
+        5 => Level::Notice,
+        4 => Level::Warning,
+        3 => Level::Error,
+        2 => Level::Critical,
+        1 => Level::Alert,
+        0 => Level::Emergency,
+    ];
+
     protected string $name;
 
     /**
@@ -287,7 +303,7 @@ class Logger implements LoggerInterface, ResettableInterface
     /**
      * Adds a log record.
      *
-     * @param  int               $level    The logging level
+     * @param  int               $level    The logging level (a Monolog or RFC 5424 level)
      * @param  string            $message  The log message
      * @param  mixed[]           $context  The log context
      * @param  DateTimeImmutable $datetime Optional log date to log into the past or future
@@ -297,6 +313,10 @@ class Logger implements LoggerInterface, ResettableInterface
      */
     public function addRecord(int|Level $level, string $message, array $context = [], DateTimeImmutable $datetime = null): bool
     {
+        if (is_int($level) && isset(self::RFC_5424_LEVELS[$level])) {
+            $level = self::RFC_5424_LEVELS[$level];
+        }
+
         if ($this->detectCycles) {
             $this->logDepth += 1;
         }
@@ -506,7 +526,7 @@ class Logger implements LoggerInterface, ResettableInterface
      *
      * This method allows for compatibility with common interfaces.
      *
-     * @param mixed             $level   The log level
+     * @param mixed             $level   The log level (a Monolog, PSR-3 or RFC 5424 level)
      * @param string|Stringable $message The log message
      * @param mixed[]           $context The log context
      *
@@ -514,11 +534,17 @@ class Logger implements LoggerInterface, ResettableInterface
      */
     public function log($level, string|\Stringable $message, array $context = []): void
     {
-        if (!is_string($level) && !is_int($level) && !$level instanceof Level) {
-            throw new \InvalidArgumentException('$level is expected to be a string, int or '.Level::class.' instance');
-        }
+        if (!$level instanceof Level) {
+            if (!is_string($level) && !is_int($level)) {
+                throw new \InvalidArgumentException('$level is expected to be a string, int or '.Level::class.' instance');
+            }
 
-        $level = static::toMonologLevel($level);
+            if (isset(self::RFC_5424_LEVELS[$level])) {
+                $level = self::RFC_5424_LEVELS[$level];
+            }
+
+            $level = static::toMonologLevel($level);
+        }
 
         $this->addRecord($level, (string) $message, $context);
     }

+ 8 - 0
tests/Monolog/Formatter/LineFormatterTest.php

@@ -141,6 +141,14 @@ class LineFormatterTest extends TestCase
         $this->assertMatchesRegularExpression('{^\['.date('Y-m-d').'] core\.CRITICAL: foobar \{"exception":"\[object] \(RuntimeException\(code: 0\): Foo at '.preg_quote(substr($path, 1, -1)).':'.(__LINE__ - 5).'\)\n\[stacktrace]\n#0}', $message);
     }
 
+    public function testInlineLineBreaksRespectsEscapedBackslashes()
+    {
+        $formatter = new LineFormatter(null, 'Y-m-d');
+        $formatter->allowInlineLineBreaks();
+
+        self::assertSame('{"test":"foo'."\n".'bar\\\\name-with-n"}', $formatter->stringify(["test" => "foo\nbar\\name-with-n"]));
+    }
+
     public function testDefFormatWithExceptionAndStacktraceParserFull()
     {
         $formatter = new LineFormatter(null, 'Y-m-d');

+ 31 - 0
tests/Monolog/LoggerTest.php

@@ -55,6 +55,37 @@ class LoggerTest extends TestCase
         $this->assertEquals(Logger::toMonologLevel('emergency'), Level::Emergency);
     }
 
+    /**
+     * @covers Monolog\Logger::addRecord
+     * @covers Monolog\Logger::log
+     */
+    public function testConvertRFC5424ToMonologLevelInAddRecordAndLog()
+    {
+        $logger = new Logger('test');
+        $handler = new TestHandler;
+        $logger->pushHandler($handler);
+
+        foreach ([
+            7 => 100,
+            6 => 200,
+            5 => 250,
+            4 => 300,
+            3 => 400,
+            2 => 500,
+            1 => 550,
+            0 => 600,
+        ] as $rfc5424Level => $monologLevel) {
+            $handler->reset();
+            $logger->addRecord($rfc5424Level, 'test');
+            $logger->log($rfc5424Level, 'test');
+            $records = $handler->getRecords();
+
+            self::assertCount(2, $records);
+            self::assertSame($monologLevel, $records[0]['level']);
+            self::assertSame($monologLevel, $records[1]['level']);
+        }
+    }
+
     /**
      * @covers Logger::__construct
      */