ソースを参照

Enable JSON encode pretty print (#1236)

Mponos George 7 年 前
コミット
daed05c3e5

+ 18 - 2
src/Monolog/Formatter/NormalizerFormatter.php

@@ -11,9 +11,9 @@
 
 namespace Monolog\Formatter;
 
-use Throwable;
 use Monolog\DateTimeImmutable;
 use Monolog\Utils;
+use Throwable;
 
 /**
  * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets
@@ -28,6 +28,8 @@ class NormalizerFormatter implements FormatterInterface
     protected $maxNormalizeDepth = 9;
     protected $maxNormalizeItemCount = 1000;
 
+    private $jsonEncodeOptions = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION;
+
     /**
      * @param ?string $dateFormat The format of the timestamp: one supported by DateTime::format
      */
@@ -89,6 +91,20 @@ class NormalizerFormatter implements FormatterInterface
         return $this;
     }
 
+    /**
+     * Enables `json_encode` pretty print.
+     */
+    public function setJsonPrettyPrint(bool $enable): self
+    {
+        if ($enable) {
+            $this->jsonEncodeOptions |= JSON_PRETTY_PRINT;
+        } else {
+            $this->jsonEncodeOptions ^= JSON_PRETTY_PRINT;
+        }
+
+        return $this;
+    }
+
     /**
      * @param  mixed                      $data
      * @return int|bool|string|null|array
@@ -247,7 +263,7 @@ class NormalizerFormatter implements FormatterInterface
      */
     private function jsonEncode($data)
     {
-        return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION);
+        return json_encode($data, $this->jsonEncodeOptions);
     }
 
     /**

+ 30 - 0
tests/Monolog/Formatter/JsonFormatterTest.php

@@ -46,6 +46,36 @@ class JsonFormatterTest extends TestCase
         $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));
     }
 
+    /**
+     * @covers Monolog\Formatter\JsonFormatter::format
+     */
+    public function testFormatWithPrettyPrint()
+    {
+        $formatter = new JsonFormatter();
+        $formatter->setJsonPrettyPrint(true);
+        $record = $this->getRecord();
+        $record['context'] = $record['extra'] = new \stdClass;
+        $this->assertEquals(json_encode($record, JSON_PRETTY_PRINT)."\n", $formatter->format($record));
+
+        $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
+        $formatter->setJsonPrettyPrint(true);
+        $record = $this->getRecord();
+        $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));
+
+        $formatter->setJsonPrettyPrint(false);
+        $record = $this->getRecord();
+        $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));
+    }
+
     /**
      * @covers Monolog\Formatter\JsonFormatter::formatBatch
      * @covers Monolog\Formatter\JsonFormatter::formatBatchJson

+ 39 - 0
tests/Monolog/Formatter/NormalizerFormatterTest.php

@@ -418,6 +418,45 @@ class NormalizerFormatterTest extends \PHPUnit\Framework\TestCase
         );
     }
 
+    /**
+     * This test was copied from `testExceptionTraceWithArgs` in order to ensure that pretty prints works
+     */
+    public function testPrettyPrint()
+    {
+        try {
+            // This will contain $resource and $wrappedResource as arguments in the trace item
+            $resource = fopen('php://memory', 'rw+');
+            fwrite($resource, 'test_resource');
+            $wrappedResource = new TestFooNorm;
+            $wrappedResource->foo = $resource;
+            // Just do something stupid with a resource/wrapped resource as argument
+            $arr = [$wrappedResource, $resource];
+            // modifying the array inside throws a "usort(): Array was modified by the user comparison function"
+            usort($arr, function ($a, $b) {
+                throw new \ErrorException('Foo');
+            });
+        } catch (\Throwable $e) {
+        }
+
+        $formatter = new NormalizerFormatter();
+        $record = ['context' => ['exception' => $e]];
+        $formatter->setJsonPrettyPrint(true);
+        $result = $formatter->format($record);
+
+        $this->assertSame(
+            '{
+    "function": "Monolog\\\\Formatter\\\\{closure}",
+    "class": "Monolog\\\\Formatter\\\\NormalizerFormatterTest",
+    "type": "->",
+    "args": [
+        "[object] (Monolog\\\\Formatter\\\\TestFooNorm)",
+        "[resource(stream)]"
+    ]
+}',
+            $result['context']['exception']['trace'][0]
+        );
+    }
+
     /**
      * @param NormalizerFormatter $formatter
      * @param \Throwable          $exception