Przeglądaj źródła

Add our own DateTime implementation to provide nicer JSON output, fixes #736

Jordi Boggiano 9 lat temu
rodzic
commit
912d813c73

+ 48 - 0
src/Monolog/DateTimeImmutable.php

@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+/**
+ * Overrides default json encoding of date time objects
+ *
+ * @author Menno Holtkamp
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class DateTimeImmutable extends \DateTimeImmutable implements \JsonSerializable
+{
+    private $useMicroseconds;
+
+    public function __construct($useMicroseconds, \DateTimeZone $timezone = null)
+    {
+        $date = null;
+        if ($useMicroseconds) {
+            $timestamp = microtime(true);
+            $microseconds = sprintf("%06d", ($timestamp - floor($timestamp)) * 1000000);
+            $date = date('Y-m-d H:i:s.' . $microseconds, $timestamp);
+        }
+        parent::__construct($date, $timezone);
+
+        $this->useMicroseconds = $useMicroseconds;
+    }
+
+    /**
+     * @return string
+     */
+    public function jsonSerialize()
+    {
+        if ($this->useMicroseconds) {
+            return $this->format('Y-m-d\TH:i:s.uP');
+        }
+
+        return $this->format('Y-m-d\TH:i:sP');
+    }
+}

+ 14 - 6
src/Monolog/Logger.php

@@ -315,12 +315,7 @@ class Logger implements LoggerInterface
             return false;
             return false;
         }
         }
 
 
-        if ($this->microsecondTimestamps) {
-            $ts = \DateTimeImmutable::createFromFormat('U.u', sprintf('%.6F', microtime(true)), $this->timezone);
-        } else {
-            $ts = new \DateTimeImmutable('', $this->timezone);
-        }
-        $ts->setTimezone($this->timezone);
+        $ts = $this->createDateTime();
 
 
         $record = array(
         $record = array(
             'message' => $message,
             'message' => $message,
@@ -560,4 +555,17 @@ class Logger implements LoggerInterface
     {
     {
         return $this->timezone;
         return $this->timezone;
     }
     }
+
+    /**
+     * Circumvent DateTimeImmutable::createFromFormat() which always returns the native DateTime instead of the specialized one
+     *
+     * @link https://bugs.php.net/bug.php?id=60302
+     */
+    private function createDateTime(): DateTimeImmutable
+    {
+        $dateTime = new DateTimeImmutable($this->microsecondTimestamps, $this->timezone);
+        $dateTime->setTimezone($this->timezone);
+
+        return $dateTime;
+    }
 }
 }

+ 2 - 1
src/Monolog/Test/TestCase.php

@@ -12,6 +12,7 @@
 namespace Monolog\Test;
 namespace Monolog\Test;
 
 
 use Monolog\Logger;
 use Monolog\Logger;
+use Monolog\DateTimeImmutable;
 
 
 /**
 /**
  * Lets you easily generate log records and a dummy formatter for testing purposes
  * Lets you easily generate log records and a dummy formatter for testing purposes
@@ -31,7 +32,7 @@ class TestCase extends \PHPUnit_Framework_TestCase
             'level' => $level,
             'level' => $level,
             'level_name' => Logger::getLevelName($level),
             'level_name' => Logger::getLevelName($level),
             'channel' => 'test',
             'channel' => 'test',
-            'datetime' => \DateTimeImmutable::createFromFormat('U.u', sprintf('%.6F', microtime(true))),
+            'datetime' => new DateTimeImmutable(true),
             'extra' => array(),
             'extra' => array(),
         );
         );
     }
     }

+ 1 - 1
tests/Monolog/Formatter/JsonFormatterTest.php

@@ -42,7 +42,7 @@ class JsonFormatterTest extends TestCase
 
 
         $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
         $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
         $record = $this->getRecord();
         $record = $this->getRecord();
-        $this->assertEquals(json_encode($record), $formatter->format($record));
+        $this->assertEquals('{"message":"test","context":[],"level":300,"level_name":"WARNING","channel":"test","datetime":"'.$record['datetime']->format('Y-m-d\TH:i:s.uP').'","extra":[]}', $formatter->format($record));
     }
     }
 
 
     /**
     /**