The Joy of Rotating Logs in Symfony
Switching from my hand-made, hodgepodge, cobbled together collection of libraries that was trying to act more and more like a "framework" every day to a full-blown real, properly developed, properly tested framework like Symfony continues to be the best decision I've made in my programming career thus far. I've learned so much about clean code, design patterns, SOLID principles and many other programming best practices from working within Symfony's MVC (Model View Controller) pattern and reading its documentation and code when I need to extend it to bow to my every whim.
One great feature of Symfony is the highly configurable logging, implemented via monolog.
Way back in my pre-Symfony days, when I encountered an exception in development, my first step was firing up xdebug and stepping through the code line by line to inspect variables and watch where the logic was taking me to try and find the root cause of the bug. Now my first step is to head to the log file and see what was happening at the time of the exception (for JSON calls, anyway. The log is spit out on the screen if the result of the call was to render a page).
I prefer text logging verses logging to a database, for the simplicity of writing and reading.
One problem with text logging is that the files can grow too big, too fast. Most text editors will choke on a log file that is too big. Or, the worst case scenario may be encountered, which is the log file becomes so large that it eats up all available disk space on the server, bringing the server to its knees. Thankfully I've only encountered this once, due to leaving a debug flag on in production. Which brings up another great thing about using Symfony, thanks to the app_dev.php file, no more debug flags.
To combat the issue of log files growing too large, one of the first things I do in any new Symfony
project is to set the log type to
rotating_file which is a standard feature in monolog, but beautifully
exposed via the Symfony configuration file.
This can be set in both your prod and dev config files, to give the desired behavior for each environment.
config_dev.yml simply change the
main handler type from
rotating_file and just
below that add the
max_files to keep. I set mine to
1 in dev, since I don't believe that a development
log file needs to persist past a single day. Voilà, a fresh clean log file every morning when I access my log
in the development environment.
# change this line
# add this line
channels: ['!event', '!doctrine', '!console']
# To follow logs in real time, execute the following command:
# `bin/console server:log -vv`
In your project's production environment configuration file -
config_prod.yml, we'll make the same changes,
but under the
nested handler. The nested handler is another great aspect of logging with monolog from inside
of a Symfony project. If the
main handler is set to a
fingers_crossed type, it caches the log for every
request. The only time that it logs anything, is if the
action_level threshold is passed. In the example below,
if a log level of error or higher is caught, it passes the cached log to the handler set in the
This allows logging of the full request stack, but only in the event that an error occurs. This way only
meaningful logs are stored, but we get the entire log for that request. This is another feature that keeps are
logs from growing too large.
# change this line
# add this line
Log files location
Another thing I like to do with the logging, is change the location of where my log files are stored. By default,
the log files are stored in
project_root/var/logs. My deployment process creates each new release in a
directory in my production environment, and my webroot is nothing more than a symlink that that points to the
most recent releases directory. If I keep the default log file location, each release uses its own directory
to store log files. By moving the logs directory up one level, each release uses a shared log location so
my log files persist across new releases of my project. Another benefit to this is not having to worry about
setting write permissions for the www-data user that Apache uses for the log directory in each new release.
It is easy to alter the
getLogDir() method in your
AppKernel class to use one level up, or any other custom
location in which you wish to store your log files.
public function getLogDir()
// I've inserted the '../' to move the logs up one directory from the project root
Easy log file viewing
As easy as it is to view log files in development, to logs in your production environment, you have to log
in to your production server, navigate to the log directory and then open them with the log viewer/text editor
of your choice. It was those couple extra steps that inspired me, after not finding any existing solutions
that I liked, to write a Symfony bundle that allows you to view your logs from your web browser.
My WebLogViewerBundle includes color-coded, collapsable log levels, and formatted JSON and SQL. It can be included via Composer (packagist) and the source can be found on GitHub.
Hopefully, you can see the benefits and ease of using rotating log files in your Symfony projects. How do you configure your logging in Symfony?If you liked this post, you can subscribe to the rss feed or follow me @ToddEidson on Twitter to be notified of future blog posts.
Date Published: 24 November, 2017