diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 3f4a4106..19fb72c5 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/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('/(? $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); } diff --git a/tests/Monolog/Formatter/LineFormatterTest.php b/tests/Monolog/Formatter/LineFormatterTest.php index 7440eda6..02c38a40 100644 --- a/tests/Monolog/Formatter/LineFormatterTest.php +++ b/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'); diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index 41bf3b6b..697518e2 100644 --- a/tests/Monolog/LoggerTest.php +++ b/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 */