Skip to content

Commit

Permalink
Handle __toString to serialize objects which are not json-serializabl…
Browse files Browse the repository at this point in the history
…e in JsonFormatter, fixes #1733
  • Loading branch information
Seldaek committed Jul 22, 2022
1 parent 284482a commit cf0f4b3
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 5 deletions.
23 changes: 18 additions & 5 deletions src/Monolog/Formatter/JsonFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,25 @@ protected function normalize($data, int $depth = 0)
return $normalized;
}

if ($data instanceof \DateTimeInterface) {
return $this->formatDate($data);
}
if (is_object($data)) {
if ($data instanceof \DateTimeInterface) {
return $this->formatDate($data);
}

if ($data instanceof Throwable) {
return $this->normalizeException($data, $depth);
}

// if the object has specific json serializability we want to make sure we skip the __toString treatment below
if ($data instanceof \JsonSerializable) {
return $data;
}

if (method_exists($data, '__toString')) {
return $data->__toString();
}

if ($data instanceof Throwable) {
return $this->normalizeException($data, $depth);
return $data;
}

if (is_resource($data)) {
Expand Down
56 changes: 56 additions & 0 deletions tests/Monolog/Formatter/JsonFormatterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Monolog\Formatter;

use JsonSerializable;
use Monolog\Logger;
use Monolog\Test\TestCase;

Expand Down Expand Up @@ -314,4 +315,59 @@ public function testEmptyContextAndExtraFieldsCanBeIgnored()
$record
);
}

public function testFormatObjects()
{
$formatter = new JsonFormatter();

$record = $formatter->format(array(
'level' => 100,
'level_name' => 'DEBUG',
'channel' => 'test',
'message' => 'Testing',
'context' => array(
'public' => new TestJsonNormPublic,
'private' => new TestJsonNormPrivate,
'withToStringAndJson' => new TestJsonNormWithToStringAndJson,
'withToString' => new TestJsonNormWithToString,
),
'extra' => array(),
));

$this->assertSame(
'{"level":100,"level_name":"DEBUG","channel":"test","message":"Testing","context":{"public":{"foo":"fooValue"},"private":{},"withToStringAndJson":["json serialized"],"withToString":"stringified"},"extra":{}}'."\n",
$record
);
}
}

class TestJsonNormPublic
{
public $foo = 'fooValue';
}

class TestJsonNormPrivate
{
private $foo = 'fooValue';
}

class TestJsonNormWithToStringAndJson implements JsonSerializable
{
public function jsonSerialize()
{
return ['json serialized'];
}

public function __toString()
{
return 'SHOULD NOT SHOW UP';
}
}

class TestJsonNormWithToString
{
public function __toString()
{
return 'stringified';
}
}

0 comments on commit cf0f4b3

Please sign in to comment.