From 3bbf17929781f8bb3bd34c9c7a80857b06914251 Mon Sep 17 00:00:00 2001
From: Andrew Berry <deviantintegral@gmail.com>
Date: Wed, 11 Jul 2012 18:21:03 -0400
Subject: [PATCH] Issue #1672740: Add a watchdog-summary command to show the
 top watchdog messages.

---
 commands/core/watchdog.drush.inc | 185 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 164 insertions(+), 21 deletions(-)

diff --git a/commands/core/watchdog.drush.inc b/commands/core/watchdog.drush.inc
index f47da67..5c5cdd2 100644
--- a/commands/core/watchdog.drush.inc
+++ b/commands/core/watchdog.drush.inc
@@ -9,6 +9,8 @@ function watchdog_drush_help($section) {
       return dt('Show available message types and severity levels. A prompt will ask for a choice to show watchdog messages.');
     case 'drush:watchdog-show':
       return dt('Show watchdog messages. Arguments and options can be combined to configure which messages to show.');
+    case 'drush:watchdog-summary':
+      return dt('Show a summary of watchdog messages. Arguments and options can be combined to configure which messages to show.');
     case 'drush:watchdog-delete':
       return dt('Delete watchdog messages. Arguments or options must be provided to specify which messages to delete.');
   }
@@ -49,6 +51,20 @@ function watchdog_drush_command() {
     ),
     'aliases' => array('wd-show', 'ws'),
   );
+  $items['watchdog-summary'] = array(
+    'description' => 'Summarize watchdog messages.',
+    'drupal dependencies' => array('dblog'),
+    'options' => array(
+      'count' => 'The number of messages to show. Defaults to 10.',
+      'severity' => 'Restrict to messages of a given severity level.',
+      'type' => 'Restrict to messages of a given type.',
+    ),
+    'examples' => array(
+      'drush watchdog-summary' => 'Show the top 10 recorded watchdog messages.',
+      'drush watchdog-summary --severity=error --type=php' => 'Show the top 10 recorded PHP errors.',
+    ),
+    'aliases' => array('wd-summary'),
+  );
   $items['watchdog-delete'] = array(
     'description' => 'Delete watchdog messages.',
     'drupal dependencies' => array('dblog'),
@@ -205,6 +221,94 @@ function drush_core_watchdog_show_many($filter = NULL) {
 }
 
 /**
+ * Generate a summary of watchdog errors. The summary is grouped by the
+ * recorded variables and can be limited by severity, type, and number of
+ * messages to return.
+ */
+function drush_core_watchdog_summary() {
+  drush_include_engine('drupal', 'environment');
+  $severities = core_watchdog_severity_levels();
+
+  $count = drush_get_option('count', 10);
+  $severity = drush_get_option('severity', FALSE);
+  if ($severity && ($level = core_watchdog_unknown_severity_level($severity)) === FALSE) {
+    return FALSE;
+  }
+
+  $type = drush_get_option('type', FALSE);
+  if ($type) {
+    if (!core_watchdog_unknown_type($type)) {
+      return FALSE;
+    }
+    $conditions[] = "type = :type";
+    $args[':type'] = $type;
+  }
+
+  // We need to GROUP BY so we can't use drush_db_select().
+  if (drush_drupal_major_version() >= 7) {
+    $query = db_select('watchdog', 'w')
+      ->distinct()
+      ->fields('w', array('type', 'message', 'variables', 'severity'))
+      ->groupBy('variables')
+      ->range(0, $count);
+
+    if ($level) {
+      $query->where('severity = :severity', array(':severity' => $level));
+    }
+    if ($type) {
+      $query->where('type = :type', array(':type' => $type));
+    }
+
+    $alias = $query->addExpression('COUNT(variables)', 'c');
+
+    $messages = $query->orderBy($alias, 'DESC')
+      ->execute()
+      ->fetchAll();
+  }
+  else {
+    $messages = array();
+    $sql = "SELECT DISTINCT type, message, variables, severity, count(variables) as c FROM {watchdog}";
+    if ($level && $type) {
+      $sql .= " WHERE severity = %d AND type = '%s'";
+    }
+    elseif ($level) {
+      $sql .= " WHERE severity = %d";
+    }
+    elseif ($type) {
+      $sql .= " WHERE type = '%s'";
+    }
+
+    $args = array();
+    if ($level) {
+      $args[] = $level;
+    }
+    if ($type) {
+      $args[] = $type;
+    }
+
+    $sql .= " GROUP BY variables ORDER BY c DESC LIMIT 10";
+    $result = db_query($sql, $args);
+    while ($message = db_fetch_object($result)) {
+      $messages[] = $message;
+    }
+  }
+
+  $rows = array(
+    array('count', 'severity', 'type', 'message'),
+  );
+
+  foreach ($messages as $message) {
+    $row = array();
+    $row[] = $message->c;
+    $row[] = $severities[$message->severity];
+    $row[] = $message->type;
+    $row[] = dt($message->message, unserialize($message->variables));
+    $rows[] = $row;
+  }
+  drush_print_table($rows, TRUE, array(5, 9, 10, 48));
+}
+
+/**
  * Format a watchdog database row.
  *
  * @param $result
@@ -326,32 +430,15 @@ function core_watchdog_query($type = NULL, $severity = NULL, $filter = NULL, $cr
   $args = array();
   $conditions = array();
   if ($type) {
-    $types = core_watchdog_message_types();
-    if (array_search($type, $types) === FALSE) {
-      $msg = "Unrecognized message type: !type.\nRecognized types are: !types.";
-      return drush_set_error('WATCHDOG_UNRECOGNIZED_TYPE', dt($msg, array('!type' => $type, '!types' => implode(', ', $types))));
+    if (!core_watchdog_unknown_type($type)) {
+      return FALSE;
     }
     $conditions[] = "type = :type";
     $args[':type'] = $type;
   }
   if (!is_null($severity)) {
-    drush_include_engine('drupal', 'environment');
-    $severities = core_watchdog_severity_levels();
-    if (isset($severities[$severity])) {
-      $level = $severity;
-    }
-    elseif (($key = array_search($severity, $severities)) !== FALSE) {
-      $level = $key;
-    }
-    else {
-      $level = FALSE;
-    }
-    if ($level === FALSE) {
-      foreach ($severities as $key => $value) {
-        $levels[] = "$value($key)";
-      }
-      $msg = "Unknown severity level: !severity.\nValid severity levels are: !levels.";
-      return drush_set_error(dt($msg, array('!severity' => $severity, '!levels' => implode(', ', $levels))));
+    if ($level = core_watchdog_unknown_severity_level($severity) === FALSE) {
+      return FALSE;
     }
     $conditions[] = 'severity = :severity';
     $args[':severity'] = $level;
@@ -367,6 +454,62 @@ function core_watchdog_query($type = NULL, $severity = NULL, $filter = NULL, $cr
 }
 
 /**
+ * Helper function to return an error when an invalid severity level is
+ * specified. This function accepts both integer and string variants of
+ * severity levels.
+ *
+ * @param $severity
+ *   The severity level to check.
+ *
+ * @return
+ *   The severity level, or return value from drush_set_error().
+ */
+function core_watchdog_unknown_severity_level($severity) {
+  drush_include_engine('drupal', 'environment');
+  $severities = core_watchdog_severity_levels();
+
+  if (isset($severities[$severity])) {
+    $level = $severity;
+  }
+  elseif (($key = array_search($severity, $severities)) !== FALSE) {
+    $level = $key;
+  }
+  else {
+    $level = FALSE;
+  }
+
+  if ($level === FALSE) {
+    foreach ($severities as $key => $value) {
+      $levels[] = "$value($key)";
+    }
+    $msg = "Unknown severity level: !severity.\nValid severity levels are: !levels.";
+    return drush_set_error(dt($msg, array('!severity' => $severity, '!levels' => implode(', ', $levels))));
+  }
+
+  return $level;
+}
+
+/**
+ * Helper function to return an error when an invalid watchdog message type is
+ * specified.
+ *
+ * @param $type
+ *   The watchdog message type to check.
+ *
+ * @return
+ *   TRUE, or the return value from drush_set_error().
+ */
+function core_watchdog_unknown_type($type) {
+  $types = core_watchdog_message_types();
+  if (array_search($type, $types) === FALSE) {
+    $msg = "Unrecognized message type: !type.\nRecognized types are: !types.";
+    return drush_set_error('WATCHDOG_UNRECOGNIZED_TYPE', dt($msg, array('!type' => $type, '!types' => implode(', ', $types))));
+  }
+
+  return TRUE;
+}
+
+/**
  * Helper function to obtain the message types based on drupal version.
  *
  * @return
-- 
1.7.11.1

