[13.x] Introduce `JsonFormatter`

Merged
CO
6mo ago
+414-5

I work in a legacy codebase that doesn't use report(), so we have a lot of this:

try {
    $this->someMethod();
} catch (\Throwable $e) {
    Log::error('Some method threw an exception :-(', [
        'exception' => $e
    ]);
}

After 6 months, I finally realized that it's not rendering public properties that I have been adding to my enriched exceptions. 🤦 It turns out that this has to do with Monolog's NormalizerFormatter which determines the shape of the array that's written to the structured log.

It would be swell if Laravel offered an easy way to always include context() inside of a log, whether it was written to logs via report() or if the exception was written as a structured log.

Perhaps the bigger benefit is the previous exception will also have its enriched context included when written to the logs.

How to use

Update your config/logging.php to use 'formatter' => Illuminate\Log\Formatters\JsonFormatter' instead of Monolog\Formatter\JsonFormatter

Output

All tests build an exception like this:

class MyException extends \RuntimeException
{
    public function context(): array
    {
        return [
            'luke' => 'cosmastech',
            'taylor' => 'taylorotwell',
        ];
    }
}

report()

Using this code

$e = new \RuntimeException(previous: new MyException);
report($e);

we get these logs:

image

Using Log

Using this code:

$e = new \RuntimeException('runtime exception', previous: new MyException);

\Log::error('Logging a nested exception', [
    'exception' => $e,
]);

This shows the before and after using this PR's JsonFormatter.

image