PSR-3: Why Drupal’s Doggone Watchdog Is Gone
by James Meickle on June 9, 2014
watchdog() provides Drupal’s out-of-the-box logging capabilities. Despite a reputation for a “learning cliff”, it’s much simpler to deal with logs in Drupal than in many other systems. Instead of dealing with confusing log files, site builders can visit the system log page in the GUI and look at neatly formatted table of error types, severities, and messages. Yay!
But did you know that as of Drupal 8.0-alpha12, watchdog() has been deprecated?
watchdog() has some limitations that become apparent the more you try to use it. Want to adjust a message before it’s sent? You need to rely on a clumsy hook_watchdog implementation – and it’s going to get every message, from every module. Want to route messages to different destinations based on their type? A hook always executes every implementation, so sending an email from your hook won’t prevent another hook from logging to the database. You need to either be comfortable with duplicate messages, or disable all other hook_watchdog implementations so that yours can handle all of the routing.
watchdog()’s reputation is worse in the high performance Drupal community. The default implementation, dblog, sends all messages to the database. These inserts can rapidly become a site’s most expensive queries, so it’s standard practice to use syslog instead. However, that introduces another problem for sites that are at scale: unlike dblog, syslog output will be different on each server, requiring a log aggregation solution. Want me to pass the yak shears?
Why don’t we hear about these problems from other web development communities? Programming language plays a large role. PHP has very few built-in logging solutions, and it’s also been historically been poor about code reuse. In contrast, Java is all about standard libraries and provides an object oriented logger out of the box. Ruby on Rails ships with its own Logger API, and alternative projects like log4r mimic it to keep the interface consistent. Python also has a robust logging module.
Recent PHP versions haven’t changed how the language treats logging, but the introduction of namespaces has had interesting downstream effects. The PHP Framework Interoperability Group (PHP-FIG) built on namespacing to provide the PSR-0 standard for class autoloading, making it much more feasible to include code from other projects. The resulting “PHP Renaissance” has brought sweeping changes to many areas over the past few years, and PHP-FIG approved the PSR-3 standard to make sure logging dependencies didn’t get in the way.
In a nutshell, PSR-3 provides a logging interface class for your code to require instead of a specific library. As long as a class satisfies that interface, it’s interchangeable – your code probably doesn’t even need to know what the class is doing. This allows you to easily swap loggers without rewriting any statements, but the real benefit kicks in when you share your code. Because your code only has a dependency on the abstraction of logging, rather than the implementation of it, you won’t force people including your code to also include a new logging library.
That’s a little abstract, so let’s think about Monolog as an example. Drupal 8 has its own logging implementation rather than reusing Monolog. However, both logging systems are accessed through a PSR-3 compliant interface. That means that you could use Monolog as a drop-in replacement for your Drupal 8 site. You don’t even have to choose between them: if you specify a factory in your own module that instantiates a Monolog instance, you can send your messages there while leaving core’s logging unmodified.
What does this mean for Drupal 8? Removing watchdog() is a compatibility break, but compared to some of the other changes in Drupal 8 it’s quite minor:
<?php // Logs a notice watchdog('my_module', $message, array()); // Logs an error watchdog('my_module', $message, array(), WATCHDOG_ERROR); ?>
<?php // Logs a notice \Drupal::logger('my_module')->notice($message); // Logs an error \Drupal::logger('my_module')->error($message); ?>
These are pretty minor changes – they will give you more flexibility in how to handle your messages, but logging will work the same way. However, this isn’t change for the sake of change; it’s a way to give back to others. We’ve brought in a lot of code from the broader PHP community, and using a PSR-3 compliant logging interface across the board will make life much easier for anyone else who wants to bring Drupal code back into their project.
If you stopped by our booth at Austin, you already got a chance to see these changes on our live Drupal 8 demo since we’ve already removed watchdog() integration from the TraceView Drupal 8 module. If you weren’t there, why not get in touch with us to book a demo? We’d be glad to show you what TraceView does for the next generation of Drupal.