Logging for MongoDB

Submitted by Frederic Marand on

One nice thing during Drupal 7/8 development is the ability, thanks to the devel module, to get a list of all SQL queries ran on a page. As I've been working quite a bit on MongoDB in PHP recently, I wondered how to obtain comparable results when using MongoDB in PHP projects. Looking at the D7 implementation, the magic happens in the Database class:

// Start logging on the default database.
define(DB_CHANNEL, 'my_logging_channel');

// Get the log contents, typically in a shutdown handler.
$log = \Database::getLog(DB_CHANNEL);

With DBTNG, that's all it takes, and devel puts it to good use UI-wise. So is there be an equivalent mechanism in MongoDB ? Of course there is !

The answer turns out to lie in the little-used, optional, third parameter to MongoClient::__construct($server, $options, $driver_options).

These driver_options can contain a context, which is a hash in which one valid key happens to be mongodb, the data for which is a hash of logging callbacks by loggable events.

Of course, there is this little issue of the PHP doc not mentioning some of the most useful events, like log_query and log_batchinsert, but once this is cleared, the logging becomes almost as simple as in Drupal:

  1. create a stream context containing these callbacks
  2. pass it to the MongoClient constructor
  3. that's it : events are now directed to your logging callbacks

This turns out not to be so much fun, though, because each of the callbacks has a specific signature, so I wrote a helper package wrapping a set of logging callbacks in a single class, and converting all of the callbacks to log to a standard PSR-3 logger. Using it, all it takes to send your MongoDB logs to your PSR-3 logger of choice is something like:

= new Emitter();
$context = $emitter->createContext();
$client = new \MongoClient($server, $options, ['context' => $context];

The code is available on Packagist/Composer, as fgm/mongodb_logger, or straight on Github as FGM/mongodb_logger. I'm quite interested in feedback on this one, as we have a pending feature request on this topic for Drupal, so feel free to comment on the Drupal issue, or send pull requests if you feel this is useful but needs some improvements.