Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Logging and error handling

On a live site you cannot show an error to a visitor, but you need to learn about it. Laravel writes errors to a log and gives the user a tidy page. Your own log messages help you see what happened before a failure.

Writing to the log

use Illuminate\Support\Facades\Log;
 
Log::info('User logged in', ['user_id' => $user->id]);
 
Log::warning('Payment succeeded on the second attempt', ['order_id' => $order->id]);
 
Log::error('The payment service is unavailable');

The second argument is an array of details. By default messages go to the storage/logs/laravel.log file.

Levels

LevelWhen to use it
debugDetails for debugging
infoOrdinary events: a login, an order
warningSomething unusual, but work continues
errorAn operation failed
criticalAn important part of the system is down

The LOG_LEVEL variable in .env sets the lowest level that gets written. Production servers usually use warning or error.

Channels

A channel decides where messages go. Channels are described in config/logging.php:

ChannelWhat it does
singleA single file
dailyA new file for every day, old ones are removed
stackSeveral channels at once
slackMessages to a Slack chat
LOG_CHANNEL=daily
LOG_LEVEL=warning

A message can be sent to a specific channel: Log::channel('slack')->critical('The site is down').

How Laravel handles errors

Laravel catches an uncaught exception itself: it writes it to the log and returns a response. With APP_DEBUG=true that is a detailed page with code and the call stack; with false it is a plain "Server error" page.

Custom error pages

Create a template named after the error code in the resources/views/errors folder:

{{-- resources/views/errors/404.blade.php --}}
<x-layout>
    <h1>Page not found</h1>
    <p>It may have been removed, or the address was mistyped.</p>
    <a href="/">Go to the home page</a>
</x-layout>

403.blade.php, 500.blade.php and 503.blade.php are made the same way.

Raising an error

abort(404);
 
abort_if(!$user->is_admin, 403);
 
abort_unless($post->is_published, 404, 'The post is not published');

The findOrFail() method raises a 404 error by itself if the record is not found.

Configuring the handling

Behavior for particular exceptions is set in the bootstrap/app.php file:

use App\Exceptions\PaymentFailed;
 
->withExceptions(function (Exceptions $exceptions) {
    $exceptions->report(function (PaymentFailed $e) {
        Log::channel('slack')->error($e->getMessage());
    });
 
    $exceptions->render(function (PaymentFailed $e, Request $request) {
        return response()->view('errors.payment', status: 402);
    });
})

report() decides how to record an exception, render() what to show the user.

Common mistake

Passwords, card numbers and tokens must not be written to the log. The log file is read by developers and support staff and is sent to third-party services. Record identifiers — user_id, order_id — rather than the data itself. And do not leave LOG_LEVEL=debug on a production server: the log grows to gigabytes.

Thanks for reading!

Donate to the site — we work hard for you.