While working on a site audit, I wanted to be able to see what errors were currently happening on the site. I checked and they had dblog enabled already with a few days of errors, but going to admin/reports/dblog showed me pages full of the same error. This can happen when there is an error that occurs on a popular page or happens on every page load and it makes the logs difficult to read. In addition to that, the overview page truncates the error message and so you need to click through to the detail page to see the entire thing.

There are contributed modules for viewing and interacting with the error log such as Better Watchdog UI and Views Watchdog, plus built into drush is drush watchdog-show. However, I was looking for something simple that 1) didn't require me to install and learn a module, and 2) got rid of the message duplication. Finding nothing that fit my needs exactly, I ended up writing a small script. This is just a simple PHP file that you run with drush scr and it spits out an HTML file.

To use it:

  • Copy the script into a text file.
  • Save it as watchdog-view.php (or whatever you’d like to call it).
  • Run it with drush scr watchdog-view.php > site-errors.html
  • Open up the site-errors.html file in your browser.
<?php

// To skip over types of messages, add them to this array.
// Example: $skip_types = array('cron', 'user');
$skip_types = array();

// Get the list of names that go with the severity levels.
$severity_levels = watchdog_severity_levels();

drush_print("<html>");
drush_print("<body>");
drush_print("<h1>WATCHDOG MESSAGES</h1>");

// Get all the message types.
$query = db_select('watchdog', 'wd')
 ->fields('wd', array('type'))
 ->distinct();

$types = $query->execute();

// Build a table for each message type.
foreach ($types as $typeobj) {
 $type = $typeobj->type;

 // If this type is one we want to skip, go to the top of the loop.
 if (in_array($type, $skip_types)) {
   continue;
 }

 // Get messages for this type, one for each location/message combo, ignoring
 // the timestamp. If you have errors that are occurring on every page load
 // and want to condense it further, omit the "location" throughout the script.
 $query = db_select('watchdog', 'wd')
   ->fields('wd', array('variables', 'location', 'message', 'severity'))
   ->condition('type', $type)
   ->orderBy('message', 'location')
   ->groupby('location', 'message', 'variables');

 $result = $query->execute();

 // Print out the messages for this type in a table.
 drush_print("<h2>Type: $type</h2>");
 drush_print('<table border="1">');
 drush_print('<tr><th>Severity</th><th>Message</th><th>Location</th></tr>');

 foreach ($result as $row) {
   if (isset($row->message) && isset($row->variables)) {
     if ($row->variables === 'N;') {
       $message = $row->message;
     }
     else {
       $message = t($row->message, unserialize($row->variables));
     }

     // Make the location clickable.
     $location = '<a href="' . $row->location . '">' . $row->location . '</a>';

     // Get the name of the severity level.
     $severity = $severity_levels[$row->severity];

     // Print out the row.
     drush_print('<tr>');
     drush_print("<td>$severity</td>");
     drush_print("<td>$message</td>");
     drush_print("<td>$location</td>");
     drush_print('</tr>');
   }
 }

 drush_print("</table>");
}

drush_print("</body>");
drush_print("</html>");

The resulting HTML page looks like a flashback to the 90s web (minus the animated gifs and blinky tags) but it’s a simple and clean overview of everything your site is currently logging.