Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.981
diff -u -r1.981 common.inc
--- includes/common.inc	31 Aug 2009 18:43:12 -0000	1.981
+++ includes/common.inc	1 Sep 2009 00:06:23 -0000
@@ -846,6 +846,15 @@
  *   The exception object that was thrown.
  */
 function _drupal_exception_handler($exception) {
+  if ($exception instanceof DrupalException) {
+    // Since the exception wasn't caught, increase the error level.
+    // Zero is the most severe, avoid overwriting it.
+    if ($exception->severity > WATCHDOG_ERROR) {
+      $exception->severity = WATCHDOG_ERROR;
+    }
+    // And set it to log.
+    $exception->shouldLog(TRUE);
+  }
   // Log the message to the watchdog and return an error page to the user.
   _drupal_log_error(_drupal_decode_exception($exception), TRUE);
 }
@@ -4212,7 +4221,7 @@
  *
  * @see drupal_render()
  * @see drupal_render_cache_set()
- * 
+ *
  * @param $elements
  *   A renderable array.
  * @return
@@ -4252,7 +4261,7 @@
  *   A renderable array.
  */
 function drupal_render_cache_set($markup, $elements) {
-  // Create the cache ID for the element 
+  // Create the cache ID for the element
   if (!in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD')) || !$cid = drupal_render_cid_create($elements)) {
     return FALSE;
   }
Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.302
diff -u -r1.302 bootstrap.inc
--- includes/bootstrap.inc	24 Aug 2009 00:14:18 -0000	1.302
+++ includes/bootstrap.inc	1 Sep 2009 00:06:19 -0000
@@ -227,6 +227,135 @@
  * @} End of "Title text filtering flags".
  */
 
+/**
+ * This Exception class is the base for all other Exception types in Drupal.
+ * By using this wrapper, you will allow global control over logging behavior,
+ * allow modules to create Exception handling hooks, etc.
+ *
+ * All custom Exception classes should extend DrupalException.
+ */
+class DrupalException extends Exception {
+  public static $loggedExceptions = array();
+
+  /**
+   * This has to default to FALSE so that if it gets turned on,
+   * the shutdown function will be registered correctly.
+   */
+  protected $shouldLog = FALSE;
+
+  /**
+   * This next block of variables are for watchdog logging.
+   */
+  public $variables = array();
+  public $severity = WATCHDOG_NOTICE;
+  public $link = NULL;
+
+  /**
+   * The parent class Exception has two params: $message and $code.
+   *
+   * To better suit the Drupal use-case, this method also supports
+   * the t() param format, for example:
+   * new DrupalException('example !var', array('!var' => 'some text'))
+   *
+   * When the params are provided in that format, $code will be set to 0.
+   * It should not need to be set to anything else often, since core doesn't
+   * use it for anything.
+   *
+   * @param $message
+   *   The message to store in the log. Keep $message translatable
+   *   by not concatenating dynamic values into it! Variables in the
+   *   message should be added by using placeholder strings alongside
+   *   the variables argument to declare the value of the placeholders.
+   *   See t() for documentation on how $message and $variables interact.
+   * @param $variables
+   *   Array of variables to replace in the message on display or
+   *   NULL if message is already translated or not possible to
+   *   translate.
+   * @param $severity
+   *   The severity of the message, as per RFC 3164.
+   * @param $link
+   *   A link to associate with the message.
+   */
+  function __construct($message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = NULL) {
+    // Avoid replacing the variables array in the object with NULL, etc.
+    if (is_array($variables)) {
+      $this->variables = $variables;
+    }
+    $this->severity = $severity;
+    $this->link = $link;
+    var_dump($severity);
+    // The Exception object expects the message and an integer code.
+    parent::__construct($message, $severity);
+  }
+
+  public function shouldLog($should_log) {
+    static $registered = FALSE;
+
+    $exception_id = spl_object_hash($this);
+
+    // Avoid registering the shutdown function multiple times if called directly.
+    if ($should_log === TRUE) {
+      if ($registered !== TRUE) {
+        // Use a shutdown function instead of a destructor so that it will
+        // be called before the DB is destructed.
+        register_shutdown_function(array('DrupalException', 'shutdown'));
+        $registered = TRUE;
+      }
+
+      // Store the exception so that it is not destroyed by the garbage collector.
+      DrupalException::$loggedExceptions[$exception_id] = $this;
+    }
+    else {
+      unset(DrupalException::$loggedExceptions[$exception_id]);
+    }
+    $this->shouldLog = $should_log;
+  }
+
+  public function addVariables($vars) {
+    if (!is_array($vars)) {
+      return;
+    }
+    foreach ($vars as $key => $value) {
+      // Because addVariables can be called more than once in different scopes
+      // as the exception bubbles up, avoid blowing out the most specific data
+      // in the event of a namespacing collision.
+      if (!isset($this->variables[$key])) {
+        $this->variables[$key] = $value;
+      }
+    }
+  }
+
+  /**
+   * Shutdown function, gets called during shutdown but before DB connection
+   * is destroyed normally.
+   *
+   * Child classes can prevent or alter logging behavior by implementing this
+   * function and not calling parent.
+   */
+  public static function shutdown() {
+    foreach (DrupalException::$loggedExceptions as $exception) {
+      $exception->logToWatchdog();
+    }
+  }
+
+  public function logToWatchdog() {
+    if ($this->shouldLog === TRUE) {
+      // Use the class the object was instanciated with as the watchdog type.
+      // Typically it will be 'DrupalException' but sometimes a child class.
+      try {
+        watchdog(
+          get_class($this),
+          $this->getMessage(),
+          $this->variables,
+          $this->severity,
+          $this->link
+        );
+      } catch (Exception $e) {
+        //NOTE: Could potentially log in a different way.
+      }
+    }
+  }
+}
 
 /**
  * Start the timer with the specified name. If you start and stop
@@ -1245,6 +1374,37 @@
 }
 
 /**
+ * Log a system message based on the contents of an Exception.
+ *
+ * @param $exception
+ *   The Exception object to log.
+ */
+function watchdog_exception($exception, $variables = array(), $severity = NULL, $link = NULL) {
+  if ($exception instanceof DrupalException) {
+    // Add the additional data to the DrupalException object.
+    $exception->addVariables($variables);
+    // Don't change the severity of the exception unless provided
+    if ($severity) {
+      $exception->severity = $severity;
+    }
+    if ($link) {
+      $exception->link = $link;
+    }
+    // DrupalExceptions have a native logging system that needs to be enabled.
+    $exception->shouldLog(true);
+    return;
+  }
+
+  // Watchdog expects a valid level, default notice.
+  if ($severity === NULL) {
+    $severity = WATCHDOG_NOTICE;
+  }
+
+  // The $exception is a different type, pull info and log immediately.
+  watchdog(get_class($exception), $exception->getMessage(), $variables, $severity, $link);
+}
+
+/**
  * Set a message which reflects the status of the performed operation.
  *
  * If the function is called with no arguments, this function returns all set
Index: modules/dblog/dblog.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/dblog/dblog.admin.inc,v
retrieving revision 1.29
diff -u -r1.29 dblog.admin.inc
--- modules/dblog/dblog.admin.inc	25 Aug 2009 10:27:14 -0000	1.29
+++ modules/dblog/dblog.admin.inc	1 Sep 2009 00:06:23 -0000
@@ -167,6 +167,10 @@
         _dblog_format_message($dblog),
       ),
       array(
+        array('data' => t('Variables'), 'header' => TRUE),
+        _dblog_format_variables($dblog->variables),
+      ),
+      array(
         array('data' => t('Severity'), 'header' => TRUE),
         $severity[$dblog->severity],
       ),
@@ -268,6 +272,17 @@
 
 
 /**
+ * Returns a screen-printable view of the variables for this entry.
+ *
+ * @param $variables
+ *  Serialized variables array from watchdog row
+ */
+function _dblog_format_variables($variables) {
+  return check_plain(var_export(unserialize($variables), TRUE));
+}
+
+
+/**
  * Return form for dblog administration filters.
  *
  * @ingroup forms
