Logging is an important part of modern application development, regardless of the platform targeted or framework used. Logging provides a window into your app, enabling transparency and visibility. With proper logging, we can proactively identify points of failure and performance bottlenecks in our app, among other things.
The Laravel framework has always come with logging configured and enabled out of the box, but Laravel 5.6 introduced a new logging system. It’s more powerful, but also a bit more complicated. In this article, we’ll explore how it works.
First, let’s review how Laravel managed logging in earlier versions.
Logging before version 5.6
Prior to version 5.6, logging was mostly file-based. Laravel supported four log outputs:
- Single files: writing all the app’s logs to a single file. This file was called
laravel.logby default, and it was located in the
- Daily files. With this, you would have a new file created for each day’s logs, resulting in the
storage/logs/folder containing files like
laravel-2018-4-28.log, and so forth.
- The system log, or syslog. This would send logs to the system logger. The location of these logs would vary depending on the operating system.
- The error log. In this mode, logs are written to your web server’s configured error log file. For instance, with Apache on a Linux OS, logs could be in
Laravel allowed you to configure the log output by setting the
log value in your
'log' => 'single', // or 'daily', 'syslog', or 'errorlog'
You could also set a minimum log level. Errors and log events which fall below this level would not be logged.
'log_level' => 'error',
Making logging first-class in Laravel 5.6
Laravel 5.6 introduces the concept of channels and stacks to allow logging to multiple locations simultaneously and provide greater customization and control to the developer.
Laravel 5.6 moves away from the file-based logging paradigm, by supporting a variety of possible log outputs, known as drivers. Supported drivers include the legacy
errorlog as well as some new ones:
slack: sends messages in realtime to a configured Slack channel
monolog: allows you to use any other Monolog log handler. For instance, you can use the
SendGridHandlerto send logs via email
custom: allows you to send logs wherever you wish. You can write a logger that sends logs to a third-party service or product such as Logstash, Apache Kafka, or even to Pusher.
Channels are log configurations which make use of drivers. For instance, in the configuration below, we have a channel named
regular that uses the
single file driver, a channel named
omg-the-house-is-on-fire that posts to
slack, and another one named
suspicious-stuff-going-on that uses a
return [ ..., 'channels' => [ 'regular' => [ 'driver' => 'single', ], 'omg-the-house-is-on-fire' => [ 'driver' => 'slack', ], 'suspicious-stuff-going-on' => [ 'driver' => 'monolog', ], ], ];
Log configuration now lives in
config/logging.php. Each log channel comes with its own configuration. This allows you to define a minimum log level for that channel only. For instance, to specify that all logs sent to the
single channel should be logged, but only those of
critical level and above should be posted to Slack, you would do this:
return [ ... 'channels' => [ 'single' => [ 'driver' => 'single', 'level' => 'debug', ], 'slack' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'level' => 'critical', ], ], ];
For channels which use the
slack driver, you’d need to set a
url, which is the webhook URL Slack provides you with. You can also set a
emoji icon for the Slack app.
You can specify the channel to send logs to by specifying the
'default' => 'single',
Logging to multiple channels
Laravel 5.6 allows us to log to multiple channels simultaneously via a driver called
stack. As the name implies, a stack combines multiple channels into one. This is extremely useful because it means you can send those critical logs to Slack or email and still have them in your regular log files for easy reference. Here’s how you can create a stack:
// config/logging.php return [ ... 'channels' => [ 'stack' => [ 'driver' => 'stack', 'name' => 'channel-name', 'channels' => ['single', 'slack'], ], 'single' => [ 'driver' => 'single', 'level' => 'debug', ], 'slack' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'level' => 'critical', ], ... ];
stack is set as your default channel, all logs would be sent to all channels registered for that stack, following their respective configurations, including the log levels. To achieve this in previous versions, you’d need to write a custom Monolog handler that combined multiple loggers.
Laravel 5.6 comes with
stack set as the default log channel and the
single sub-channel registered on the stack.
Writing log messages
While Laravel automatically logs all uncaught errors and exceptions thrown in your app, sometimes you may wish to log specific information or handle errors in a custom way. You can send logs manually using the
Log facade (
Log::emergency($message); Log::alert($message); Log::critical($message); Log::error($message); Log::warning($message); Log::notice($message); Log::info($message); Log::debug($message);
The provided methods correspond to the various possible log levels, as defined by a specification.
Using these methods will send logs to your configured
default channel. If you need to log to a specific channel rather than the default, you can call the
channel method first:
Even better, you can create a stack dynamically using the
Log::stack(['suspicious-activity', 'slack'])->info("We're being attacked!");
Logging is an important part of software engineering. The twelve-factor manifesto treats proper logging as one of the key concerns of a modern app and gives a few tips on how logs should be treated. With these new logging features in Laravel, it’s easier than ever before to track down errors and improve your development experience as a whole.