From 68cf3c69d11ea3366564ab29a4f7ddd579bb59d7 Mon Sep 17 00:00:00 2001 From: Tom Rochette Date: Fri, 5 Jan 2018 14:38:31 -0500 Subject: [PATCH] Allow JsonFormatter maximum normalized depth and maximum number of items per level to be configured in the constructor. --- src/Monolog/Formatter/JsonFormatter.php | 36 ++++++++++++++-- tests/Monolog/Formatter/JsonFormatterTest.php | 41 +++++++++++++++++++ 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 8e2f2fdd..1fcfd579 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -27,6 +27,8 @@ class JsonFormatter extends NormalizerFormatter protected $batchMode; protected $appendNewline; + protected $maxNormalizeDepth = 9; + protected $maxNormalizeItemCount = 1000; /** * @var bool @@ -59,6 +61,32 @@ class JsonFormatter extends NormalizerFormatter return $this->appendNewline; } + /** + * The maximum number of normalization levels to go through + */ + public function getMaxNormalizeDepth(): int + { + return $this->maxNormalizeDepth; + } + + public function setMaxNormalizeDepth(int $maxNormalizeDepth): void + { + $this->maxNormalizeDepth = $maxNormalizeDepth; + } + + /** + * The maximum number of items to normalize per level + */ + public function getMaxNormalizeItemCount(): int + { + return $this->maxNormalizeItemCount; + } + + public function setMaxNormalizeItemCount(int $maxNormalizeItemCount): void + { + $this->maxNormalizeItemCount = $maxNormalizeItemCount; + } + /** * {@inheritdoc} */ @@ -122,8 +150,8 @@ class JsonFormatter extends NormalizerFormatter */ protected function normalize($data, int $depth = 0) { - if ($depth > 9) { - return 'Over 9 levels deep, aborting normalization'; + if ($depth > $this->maxNormalizeDepth) { + return 'Over '.$this->maxNormalizeDepth.' levels deep, aborting normalization'; } if (is_array($data) || $data instanceof \Traversable) { @@ -131,8 +159,8 @@ class JsonFormatter extends NormalizerFormatter $count = 1; foreach ($data as $key => $value) { - if ($count++ >= 1000) { - $normalized['...'] = 'Over 1000 items, aborting normalization'; + if ($count++ >= $this->maxNormalizeItemCount) { + $normalized['...'] = 'Over '.$this->maxNormalizeItemCount.' items, aborting normalization'; break; } $normalized[$key] = $this->normalize($value, $depth + 1); diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index 6dfdbb7a..699c27a3 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -110,6 +110,47 @@ class JsonFormatterTest extends TestCase $this->assertContextContainsFormattedException($formattedThrowable, $message); } + public function testMaxNormalizeDepth() + { + $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, true); + $formatter->setMaxNormalizeDepth(1); + $throwable = new \Error('Foo'); + + $message = $this->formatRecordWithExceptionInContext($formatter, $throwable); + + $this->assertContextContainsFormattedException('"Over 1 levels deep, aborting normalization"', $message); + } + + public function testMaxNormalizeItemCountWith0ItemsMax() + { + $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, true); + $formatter->setMaxNormalizeDepth(9); + $formatter->setMaxNormalizeItemCount(0); + $throwable = new \Error('Foo'); + + $message = $this->formatRecordWithExceptionInContext($formatter, $throwable); + + $this->assertEquals( + '{"...":"Over 0 items, aborting normalization"}'."\n", + $message + ); + } + + public function testMaxNormalizeItemCountWith3ItemsMax() + { + $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, true); + $formatter->setMaxNormalizeDepth(9); + $formatter->setMaxNormalizeItemCount(3); + $throwable = new \Error('Foo'); + + $message = $this->formatRecordWithExceptionInContext($formatter, $throwable); + + $this->assertEquals( + '{"level_name":"CRITICAL","channel":"core","...":"Over 3 items, aborting normalization"}'."\n", + $message + ); + } + /** * @param string $expected * @param string $actual