Laravel

Logging in Laravel

An overview of Laravel's logging system covering log levels, channels, stacking multiple channels, and best practices for writing structured log messages.

Laravel wraps the popular Monolog library behind a clean, unified interface. You get multiple log channels out of the box — file, single, daily, syslog, errorlog, and others — and you can stack or aggregate them however you like.

Log Levels

Laravel supports the standard PSR-3 log levels, from least to most severe:

  • debug — detailed diagnostic information
  • info — general operational events
  • warning — something unexpected happened, but the application can continue
  • error — a runtime error that prevents a specific operation
  • critical — a serious error; the application may be unable to continue
  • alert — action must be taken immediately
  • emergency — the system is unusable

Basic Usage

The Log facade gives you immediate access to the default channel:

use Illuminate\Support\Facades\Log;

Log::info('User logged in', ['user_id' => $user->id]);
Log::warning('Disk space running low', ['percent_used' => 87]);
Log::error('Payment failed', ['order_id' => $order->id, 'reason' => $e->getMessage()]);

The second argument is a context array. It gets serialised alongside the message and makes logs searchable and debuggable.

Configuring Channels

Log channels are defined in config/logging.php. Laravel ships with several defaults:

// config/logging.php
return [
    'default' => env('LOG_CHANNEL', 'stack'),

    'channels' => [
        'stack' => [
            'driver'   => 'stack',
            'channels' => ['single', 'slack'],
        ],

        'single' => [
            'driver' => 'single',
            'path'   => storage_path('logs/laravel.log'),
            'level'  => 'debug',
        ],

        'daily' => [
            'driver'   => 'daily',
            'path'     => storage_path('logs/laravel.log'),
            'level'    => 'info',
            'days'     => 14,
        ],

        'slack' => [
            'driver' => 'slack',
            'url'    => env('SLACK_WEBHOOK_URL'),
            'level'  => 'critical',
        ],
    ],
];

The stack channel fans a single log call out to multiple channels. This is the recommended default for production — write to a file and alert on Slack for critical errors, for example.

Selecting a Channel at Runtime

You can target a specific channel without changing the default:

Log::channel('daily')->info('This goes only to the daily file');
Log::channel('slack')->critical('Alerting the team via Slack');

Contextual Logging

Attach context that applies to every subsequent log call within a block using withContext:

Log::withContext(['request_id' => $requestId, 'user_id' => auth()->id()]);

// All log calls in this request now include request_id and user_id
Log::info('Processing order');
Log::error('Something went wrong');

For even more granular control, create a logger instance scoped to a specific channel and context:

$logger = Log::channel('daily');
$logger->info('Order created', ['order_id' => $order->id]);

Writing a Custom Log Channel

If none of the built-in drivers suit your needs, create a custom channel using a handler class:

// config/logging.php
'datadog' => [
    'driver' => 'custom',
    'via'    => App\Logging\DatadogLogger::class,
],
namespace App\Logging;

use Monolog\Logger;

class DatadogLogger
{
    public function __invoke(array $config): Logger
    {
        $logger = new Logger('datadog');
        $logger->pushHandler(new \App\Logging\DatadogHandler());

        return $logger;
    }
}

Tips

  • Always pass context as the second argument rather than embedding variables in the message string. It makes logs structured and machine-parseable.
  • Set the log level for each channel appropriately. You rarely want debug level in production — it generates enormous amounts of output.
  • In CI and containerised deployments, the errorlog driver writes to PHP's error output, which your orchestrator (Docker, Kubernetes) can capture and forward.
  • Rotate logs in production. The daily driver handles this automatically, keeping only the number of days you configure.
← Older
Mass Assignment Guarding in Laravel
Newer →
Laravel Pint: Code Style Formatting

Newsletter

A weekly newsletter on React, Next.js, AI-assisted development, and engineering. No spam, unsubscribe any time.