In any application, a developer needs to be able to see what’s going on while the application is in use to debug issues as they arise and to identify opportunities for improvement. For this purpose, developers use logging for greater insight into what’s going on inside the application while it’s in use.
When implementing any logging solution, it’s important to have enough logging to be able to capture vital information and metrics but not over-log such that any important information is lost in a sea of data.
In this article, you’ll look at how to implement logging in the popular PHP framework Laravel. Laravel is a Model-View-Controller PHP framework that allows developers to create anything from small-scale websites to enterprise-level applications quickly and easily.
After learning about how Laravel helps developers manage their logs, you’ll take a look at some best practices and specific tooling that you need to debug Laravel applications
Getting Started with Logs in Laravel
As you begin to implement logging in your Laravel application, the first challenge is deciding what to log. Much like commenting code, comments in certain places within the codebase can be helpful, while commenting on every line can clutter up the codebase, making it difficult to work with.
Common logging priorities in applications include API responses in calls to external services, any queries or application behavior that is happening more slowly than expected, and at the very minimum, notices and errors produced by either Laravel or PHP. The goal of logs is two-fold: capture errors so that they can be debugged even if they can’t be reproduced in real time and identify areas for improvement within the application, which is where notices and PHP-level warnings come in handy.
Events that need to be logged come in different severities, and most loggers, including Laravel’s, define what are known as log levels. These agreed-upon levels are defined in a document known as RFC 5424 and are available in Laravel’s log facade. They include emergency, alert, critical, error, warning, notice, info, and debug, and are defined in Laravel as seen below:
You can call any of these methods to log a message for the corresponding level. By default, the message will be written to the default log channel as configured by your <terminal inline>logging<terminal inline> configuration file.
When you’re using Laravel’s built-in log facade, Laravel uses log channels as a way to record where you send your information. Log channels can do many things, including sending log messages to the standard system log or pushing log to Papertrail or even sending log entries as Slack messages (although this should probably be reserved for truly critical log messages).
Laravel Logging Best Practices
When using Laravel’s default log facade, it’s relatively simple to start inserting log statements at crucial points in your application; however, if a few key points aren’t considered up front, these logs can quickly grow to be unusable and a security risk.
Structuring, Storing, and Outputting Logs
Depending on how frequently you’re writing to log files, they can grow in size rapidly to the point that any application used for reading or filtering through them might start to struggle to parse the amount of information stored. Most logs use a concept of log rotation, where log files are automatically compressed, archived, renamed, or deleted either when they reach a certain size or on a calendar schedule. This ensures that no one log file gets too big to be useful. If the log files are archived or stored somewhere else, that means they can be accessed if the historical data is truly necessary, but only the most up-to-date (and therefore, likely to be most useful) information is retained where it can be easily accessed.
Under the hood, many PHP frameworks use the Monolog library and it’s become largely standard in the PHP ecosystem. Instead of writing logs manually, Monolog lets developers easily write to and manage their log files by providing a standard interface for logging. This allows developers to create loggers that write to various log channels and focus on their application logic instead of having to spend unnecessary time writing custom logging code.
Once you have storage under control, you need a way to read your logs. While most logs are stored in plain text and can be opened in any text editor, a dedicated log reader has features that a standard text editor doesn’t. For example, there is a Laravel-specific package called Laravel Log Viewer, which can be installed via Composer, that can expose your logs via a route or customized view and can be worked with more effectively.
Laravel’s config/logging.php File
The <terminal inline>config/logging.php<terminal inline> file is, unsurprisingly, where the majority of the logging for your Laravel application is configured. If you create a brand-new Laravel app, you’ll see that there are default values in there for many of the log settings that Laravel supports, with a default log channel as well as sample configurations for some of the others. For example, at the top of the file, you’ll see something like the following:
This code sets up the default log channel for Laravel. If you have a value for <terminal inline>LOG_CHANNEL<terminal inline> in your <terminal inline>.env<terminal inline> file, it will use that; otherwise, it will fall back to the stack log channel. Below this default value is an array of all the various log channels that can be configured.
While changing something about what your application is logging needs to happen surrounding the code that you want logged, any changes to how your application is logging should be made and centralized in the <terminal inline>config/logging.php<terminal inline> file. This way, other developers know where to look for these settings should they need to be changed in the future.
A common way all companies (including high-profile ones) unknowingly leak information is through logging. If you’re not careful as a developer, sensitive personal information, including passwords, can get logged to a log file, which is usually kept under less-intensive security than passwords that are stored in a database or some other system.
For example, if you’re trying to debug information related to a user and log out the entire user object, information about that user can be stored in the logs. If these logs are leaked or accessed in an unauthorized way in the future, then all that logged user’s information is also leaked. Depending on what information you’re storing about the user, this could have serious personal implications as well as potentially create legal and financial liability for the owner of the application. Luckily, there are PHP packages that you can include with your application to mask this data. However, it’s still worth auditing your logs every once in a while to make sure no sensitive information has been stored there.
Common Third-Party Tools for Logging
The default Laravel logging setup is easy to get started with, but as applications get more complicated and distributed, this basic logging sometimes isn’t enough to provide developers with the information they need to keep their applications running smoothly.
Developers often use tools like Papertrail to keep track of their logs or New Relic to give them observability into what’s going on with their application. However, when you get into complex deployments on infrastructure involving Kubernetes, things get a bit more complicated. That’s where ContainIQ can help.
Using ContainIQ for Laravel Applications
As a logging solution, ContainIQ lets you dig even deeper into your code and infrastructure by monitoring your application directly from the kernel, providing developers with more specific logging at the cluster level and application level. With other logging tools that aren’t as Kubernetes-native, you may get certain parts of your application logging errors when, really, the error is at the infrastructure level. This could send you down a rabbit hole of investigation that ultimately isn’t going to produce results.
Beyond allowing developers to pinpoint problems quicker, ContainIQ also helps developers decide what to pay attention to and what can be safely ignored. Using historical data, teams can set more intelligent alerts to avoid alert fatigue and ensure only information that needs to be addressed makes its way to developers who can make the necessary changes.
Once an alert fires and a change needs to be made, ContainIQ brings all the necessary information into one place. Laravel applications today are complex, and tracking down a solution to a logged issue often involves comparing multiple sets of logs for your application, infrastructure, and sometimes even external providers. However, ContainIQ can store data from multiple sources in one platform, which lets users correlate events from multiple sets of logs without having to manually compare timestamps.
This is especially important when trying to figure out why certain errors are happening in the context of your Kubernetes infrastructure. Because ContainIQ can help you visualize your entire Kubernetes setup and pinpoint specific nodes where you see errors, you can quickly find out what’s going on and get issues resolved.
Whether your application has gotten more complicated than can be effectively debugged with Laravel’s default logging or whether debugging and resolving issues is taking far too long and producing far too much uncertainty, ContainIQ can be the step-up you need to take your Laravel logging to the next level.
Logs are an important feature in any application stack, and applications built with Laravel are no exception. While Laravel does provide a robust log facade out of the box that can handle base-level logging and can push that log data to a variety of sources, when your application gets more complicated and deployed on an infrastructure like Kubernetes, you need a more specific solution.
ContainIQ provides a wide-ranging set of logging tools, and with it, you can be sure your developers are getting the insight they need to debug and improve their applications quickly and accurately.