yoeriboven / laravel-log-db

A database driver for logging with Laravel
MIT License
45 stars 13 forks source link

Exceptions produce an empty object in the log #6

Closed lriggle-strib closed 1 year ago

lriggle-strib commented 1 year ago

When the system logs an exception (either thrown, or caught and manually logged), the exception data is empty in the database.

What I'm using

Laravel: 9.x PHP: 8.1

Expected Behavior

Logging an exception will generate a log record in the database that includes data from the exception.

Observed Behavior

Logging an exception will generate a log record in the database that includes an empty object for the exception

Here is the output from a thrown exception after being recorded in the database.

39,ERROR,400,test,'{"exception": {}}',[],2022-12-25 19:12:33

Possible Resolution Options

Locally, I tested out two methods to resolution, both of which involved extending the DatabaseHandler class to do them.

  1. Call the __toString() function from the exception object. This generates output similar to what is found in the log files.
  2. This is what I ended up doing because having the data formatted like this was most useful to me: create a new array and add the message and stack trace data to that array.
[
    'message' => $exception->getMessage(),
    'trace' => $exception->getTrace(),
 ]

Replacing the exception object with the above will generate a log record that looks like this:

40,ERROR,400,Test Log,'{"exception": {"message": "test", "trace": [{"file": "/srv/vendor/laravel/framework/src/Illuminate/Routing/Controller.php", "line": 54, "type": "->", "class": "App\\Http\\Controllers\\HomeController", "function": "index"}, {"file": "/srv/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php", "line": 43, "type": "->", "class": "Illuminate\\Routing\\Controller", "function": "callAction"}, ...]}}',[],2022-12-25 19:24:22

Here is the full function I modified:

    protected function write( array $record ): void
    {
        $exception = null;
        if ( isset( $record[ 'context' ][ 'exception' ] ) ) {
            $exception = $record[ 'context' ][ 'exception' ];
        }

        if ( $exception instanceof Throwable ) {
            //If I was calling $exception->__toString(), I'd do that here as well
            $record[ 'context' ][ 'exception' ] = [
                'message' => $exception->getMessage(),
                'trace' => $exception->getTrace()
            ];
        }

        LogMessage::create( [
            'level' => $record[ 'level' ],
            'level_name' => $record[ 'level_name' ],
            'message' => $record[ 'message' ],
            'logged_at' => $record[ 'datetime' ],
            'context' => $record[ 'context' ],
            'extra' => $record[ 'extra' ],
        ] );
    }
yoeriboven commented 1 year ago

First of all, sorry this took a while.

Second of all, this is a fantastic issue. I wish all issues / technical problems were written like this. Thank you so much for the clear explanation and even providing a possible solution.

I fixed the issue and it is now available in v1.1.1. It now also comes with Laravel 10 support. Let me know if you get issues with the update. I'll try to fix them a little faster than this time 😉