From efea1d6a34f025e5817353c4be07f10b6b057cb3 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Jun 2024 11:50:33 +0300 Subject: [PATCH 1/2] Add `DateTime` and `DateTimeImmutable` support as time in log context --- CHANGELOG.md | 1 + src/Message/Formatter.php | 36 +++++++++++++++++----- tests/Message/FormatterTest.php | 54 +++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0acbc517..d5fb3933 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - New #109: Add context provider (@vjik) - Chg #109: Deprecate `Logger` methods `setTraceLevel()` and `setExcludedTracePaths()` in favor of context provider usage (@vjik) +- New #111: Add `DateTime` and `DateTimeImmutable` support as time in log context (@vjik) ## 2.0.0 May 22, 2022 diff --git a/src/Message/Formatter.php b/src/Message/Formatter.php index 29063130..e01d100d 100644 --- a/src/Message/Formatter.php +++ b/src/Message/Formatter.php @@ -5,6 +5,9 @@ namespace Yiisoft\Log\Message; use DateTime; +use DateTimeInterface; +use Exception; +use LogicException; use RuntimeException; use Yiisoft\Log\Message; use Yiisoft\VarDumper\VarDumper; @@ -140,16 +143,33 @@ private function defaultFormat(Message $message, array $commonContext): string */ private function getTime(Message $message): string { - /** @psalm-suppress PossiblyInvalidCast */ - $timestamp = (string) $message->context('time', microtime(true)); + $time = $message->context('time'); - $format = match (true) { - str_contains($timestamp, '.') => 'U.u', - str_contains($timestamp, ',') => 'U,u', - default => 'U', - }; + if (is_int($time) || is_float($time)) { + try { + $date = new DateTime('@' . $time); + } catch (Exception $e) { + throw new LogicException('Invalid time value in log context: ' . $time . '.', previous: $e); + } + } elseif (is_string($time)) { + $format = match (true) { + str_contains($time, '.') => 'U.u', + str_contains($time, ',') => 'U,u', + default => 'U', + }; + $date = DateTime::createFromFormat($format, $time); + if ($date === false) { + throw new LogicException('Invalid time value in log context: "' . $time . '".'); + } + } elseif ($time instanceof DateTimeInterface) { + $date = $time; + } elseif ($time === null) { + $date = new DateTime(); + } else { + throw new LogicException('Invalid time value in log context. Got "' . get_debug_type($time) . '".'); + } - return DateTime::createFromFormat($format, $timestamp)->format($this->timestampFormat); + return $date->format($this->timestampFormat); } /** diff --git a/tests/Message/FormatterTest.php b/tests/Message/FormatterTest.php index 1cc16de2..bd71a828 100644 --- a/tests/Message/FormatterTest.php +++ b/tests/Message/FormatterTest.php @@ -4,7 +4,9 @@ namespace Yiisoft\Log\Tests\Message; +use DateTime; use Exception; +use LogicException; use PHPUnit\Framework\TestCase; use Psr\Log\LogLevel; use RuntimeException; @@ -262,4 +264,56 @@ public function testFormatMessageThrowExceptionForPrefixCallableReturnNotString( $this->expectException(RuntimeException::class); $this->formatter->format(new Message(LogLevel::INFO, 'test', ['foo' => 'bar']), []); } + + public static function dataTime(): array + { + return [ + 'int' => ['1970-01-01 00:00:01.000000', 1], + 'float' => ['1970-01-01 00:00:01.230000', 1.23], + 'string-int' => ['1970-01-01 00:00:23.000000', '23'], + 'string-float' => ['1970-01-01 00:00:23.600000', '23.6'], + 'string-float-comma' => ['1970-01-01 00:00:23.600000', '23,6'], + 'datetime' => ['1970-01-01 00:00:23.00000', new DateTime('@23')], + ]; + } + + /** + * @dataProvider dataTime + */ + public function testTime(string $expected, mixed $value): void + { + $formatter = new Formatter(); + $result = $formatter->format(new Message(LogLevel::INFO, 'test', ['time' => $value]), []); + $this->assertStringStartsWith($expected, $result); + } + + public function testTimeWithInvalidFloat(): void + { + $formatter = new Formatter(); + $message = new Message(LogLevel::INFO, 'test', ['time' => 1234231.9135123512]); + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Invalid time value in log context: 1234231.9135124.'); + $formatter->format($message, []); + } + + public function testTimeWithInvalidString(): void + { + $formatter = new Formatter(); + $message = new Message(LogLevel::INFO, 'test', ['time' => 'hello']); + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Invalid time value in log context: "hello".'); + $formatter->format($message, []); + } + + public function testTimeWithInvalidType(): void + { + $formatter = new Formatter(); + $message = new Message(LogLevel::INFO, 'test', ['time' => []]); + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Invalid time value in log context. Got "array".'); + $formatter->format($message, []); + } } From 833816380526e7a0e51b43edd257abd21bd5b546 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Tue, 18 Jun 2024 08:51:04 +0000 Subject: [PATCH 2/2] Apply fixes from StyleCI --- src/Message/Formatter.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Message/Formatter.php b/src/Message/Formatter.php index e01d100d..f54685e7 100644 --- a/src/Message/Formatter.php +++ b/src/Message/Formatter.php @@ -17,7 +17,6 @@ use function is_string; use function is_object; use function method_exists; -use function microtime; use function sprintf; /**