So logging useful data is hard, logging useful data in a manner that makes it accessible is ever harder. Often we only log the exceptions thrown because that’s the route of the problem when in fact we need to see the entire history of the logs during a request, not just the stack trace of what made the application crash.

Imagine this scenario, your customer is using your site happily and then they attempt something to only receive a big 500 server error page. There’s no context on the page, nothing to help them fix the issue. If they’re not very technical themselves they have to find a way of describing what they were doing as they contact your company’s support for answers.

What would be better instead is if you can provide your customer with an error code at the point of failure. Then your support team can be provided with that code for a developer to match with the logs data from the request which produced the error. Giving you an instant point to start investigating with.

When developing in symfony we can create a “fingers crossed” Monolog handler and we could do the same in Laravel but the setup I’m going to show you something else that works an is a little bit easier to set up. In theory this should work with all Laravel 5.0+ projects.

Setting up a message logged event listener

To begin with we need to collect all the log messages as they’re made. Laravel’s logging system already handles the dispatch of these so we only need to make a listener for them. This can be achieved with:

php artisan make:listener LoggingListener -e Illuminate\\Log\\Events\\MessageLogged

Then edit the listener as shown in the example. We’ll simply add a collection where we can push those MessageLogged events to use later on should a fatal exception occur.

We also need to modify the EventServiceProvider namely the listen property to make sure that MessageLogged events get delivered to our new LoggingListener listener.

Also we need to make our listener a singleton otherwise we won’t be able to access the events collected as when we fetch the listener from the container we’ll receive a listener with an empty collection. For this only one line needs to be added which I’ve added to the AppServiceProvider .

Modifying the exception handler

Now we have our collection of MessageLogged events we need to modify our application exception handler to report the exception with the logs and output the error code for the user to see. This class is found in app/Exceptions/Handler.php which by default should have two methods in there, report and render .

To quickly summarise these two function, report happens first, the idea of it is to be able to send the exception to some kind of external service in the event of a failure. You can read more about this in the official docs. The render function is simply how you present an error page to the user upon a critical error. We won’t change the render function but we will have to alter the process by overriding the renderHttpException method in the parent class.

You’ll see in the report function I’ve added just a simple mechanism for storing the report to the local disk in a json file. This is purely for demonstration purposes. You could do any number of things with the events to make easier to analyse. Also for generating a unique ID I simply choose to use str_random which is provided by Laravel but in all honest you can use anything you like, just make sure it’s going to be unique enough that you don’t end up with multiple users with the same code.

As for adding the renderHttpException method, the code in the example is near identical to what’s in the parent class except for instead of just passing the variables errors and exception to the view we now also provide a errorCode variable.

Adding an error page to display the code

Of course the last part is that we need to have an error view which will display the error code we’re generating.

Any errors thrown should now end up looking something like the screenshot below.