Index: syslog/syslog.module
===================================================================
--- syslog/syslog.module	(revision 0)
+++ syslog/syslog.module	(revision 0)
@@ -0,0 +1,106 @@
+<?php
+// $Id$
+
+if (defined('LOG_LOCAL0')) {
+  define('DEFAULT_SYSLOG_FACILITY', LOG_LOCAL0);
+}
+else {
+  define('DEFAULT_SYSLOG_FACILITY', LOG_USER);
+}
+
+/**
+ * @file
+ * Redirects logging messages to syslog.
+ */
+
+define('SYSLOG_FACILITY', 'syslog_facility');
+/**
+ * Implementation of hook_help().
+ */
+function syslog_help($section) {
+  switch ($section) {
+    case 'admin/help#syslog':
+      return '<p>'. t('Provides the facility to log Drupal messages to the operating systems\' syslog facility.') .'</p>';
+  }
+}
+
+function syslog_menu() {
+  $items[] = array(
+    'path'           => 'admin/settings/logging/syslog',
+    'title'          => t('Syslog'),
+    'description'    => t('Settings for syslog logging. Syslog is a system administration logging tool, where messages are routed by facility and severity. It is more suitable for medium to large sites, and would not be suitable for shared hosting environments.'),
+    'callback'       => 'drupal_get_form',
+    'callback arguments' => array('syslog_admin_settings'),
+  );
+  return $items;
+}
+
+function syslog_admin_settings() {
+  $form[SYSLOG_FACILITY] = array(
+    '#type'          => 'select',
+    '#title'         => t('Syslog facility to send events to'),
+    '#default_value' => variable_get('syslog_facility', DEFAULT_SYSLOG_FACILITY),
+    '#options'       => syslog_facility_list(),
+    '#description'   => t('Select the syslog facility to send Drupal\'s messages to. Syslog is a system administration logging tool, where messages are routed by facility and severity. It is more suitable for medium to large sites, and would not be suitable for shared hosting environments. In the file /etc/syslog.conf you define where messages go for any combination of facility and severity. For UNIX/Linux systems, Drupal can use the facilities user, local0 to local7, for Windows, you can only use the user facility. For more information on syslog facilities, severity levels, and how to setup a syslog.conf files, see !syslog_conf and !php', array(
+      '!php'         => l("PHP's syslog", 'http://www.php.net/manual/en/function.openlog.php'),
+      '!syslog_conf' => l('UNIX/Linux syslog.conf', 'http://www.rt.com/man/syslog.5.html'),
+      )),
+  );
+  return system_settings_form($form);
+}
+
+function syslog_facility_list() {
+  $facility_list = array(
+    LOG_USER   => t('LOG_USER - User level messages. Use this for Windows.'),
+  );
+  if (defined('LOG_LOCAL0')) {
+    $facility_list += array(
+      LOG_LOCAL0 => t('LOG_LOCAL0 - Local 0'),
+      LOG_LOCAL1 => t('LOG_LOCAL1 - Local 1'),
+      LOG_LOCAL2 => t('LOG_LOCAL2 - Local 2'),
+      LOG_LOCAL3 => t('LOG_LOCAL3 - Local 3'),
+      LOG_LOCAL4 => t('LOG_LOCAL4 - Local 4'),
+      LOG_LOCAL5 => t('LOG_LOCAL5 - Local 5'),
+      LOG_LOCAL6 => t('LOG_LOCAL6 - Local 6'),
+      LOG_LOCAL7 => t('LOG_LOCAL7 - Local 7'),
+    );
+  }
+  return $facility_list;
+}
+
+function syslog_watchdog($log_entry) {
+  static $log_init = FALSE;
+
+  if (!$log_init) {
+    $log_init = TRUE;
+    openlog('drupal', LOG_NDELAY, variable_get('syslog_facility', DEFAULT_SYSLOG_FACILITY));
+  }
+
+  syslog($log_entry['severity'], theme('syslog_format', $log_entry));
+}
+
+function syslog_theme() {
+  return array(
+    'syslog_format' => array(
+      'arguments' => array('log_msg' => NULL),
+    ),
+  );
+}
+
+function theme_syslog_format($log_msg) {
+  global $base_url;
+
+  $message = t('@base_url|@timestamp|@type|@uid|@ip|@request_uri|@referer_uri|@link|@message',
+    array(
+      '@base_url'    => $base_url,
+      '@timestamp'   => $log_msg['timestamp'],
+      '@type'        => $log_msg['type'],
+      '@ip'          => $log_msg['ip'],
+      '@request_uri' => $log_msg['request_uri'],
+      '@referer_uri' => $log_msg['referer'],
+      '@uid'         => $log_msg['user']->uid,
+      '@link'        => strip_tags($log_msg['link']),
+      '@message'     => strip_tags($log_msg['message']),
+    ));
+  return $message;
+}
Index: syslog/syslog.info
===================================================================
--- syslog/syslog.info	(revision 0)
+++ syslog/syslog.info	(revision 0)
@@ -0,0 +1,5 @@
+; $Id$
+name = Syslog
+description = Logs and records system events to syslog.
+package = Core - optional
+version = VERSION
Index: system/system.module
===================================================================
--- system/system.module	(revision 1132)
+++ system/system.module	(working copy)
@@ -227,6 +227,11 @@
       'callback' => 'drupal_get_form',
       'callback arguments' => array('system_error_reporting_settings'));
     $items[] = array(
+      'path' => 'admin/settings/logging',
+      'title' => t('Logging and alerts'),
+      'description' => t('Settings for logging and alerts modules. Various modules can route Drupal\'s system events to different destination, such as syslog, database, email, ...etc.'),
+      'callback' => 'system_logging_overview');
+    $items[] = array(
       'path' => 'admin/settings/performance',
       'title' => t('Performance'),
       'description' => t('Enable or disable page caching for anonymous users, and enable or disable CSS preprocessor.'),
@@ -637,16 +642,6 @@
     '#description' =>  t('Where Drupal, PHP and SQL errors are logged. On a production server it is recommended that errors are only written to the error log. On a test server it can be helpful to write logs to the screen.')
   );
 
-  $period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200), 'format_interval');
-  $period['1000000000'] = t('Never');
-  $form['watchdog_clear'] = array(
-    '#type' => 'select',
-    '#title' => t('Discard log entries older than'),
-    '#default_value' => variable_get('watchdog_clear', 604800),
-    '#options' => $period,
-    '#description' => t('The time log entries should be kept. Older entries will be automatically discarded. Requires crontab.')
-  );
-
   return system_settings_form($form);
 }
 
@@ -1329,7 +1324,7 @@
   }
 
   // Merge in required modules.
-  $modules_required = array('block', 'filter', 'node', 'system', 'user', 'watchdog');
+  $modules_required = array('block', 'filter', 'node', 'system', 'user');
   foreach ($modules_required as $required) {
     $disabled[] = $required;
     $form['disabled_modules']['#value'][$required] = TRUE;
@@ -1912,6 +1907,14 @@
   return $output;
 }
 
+function system_logging_overview() {
+  $item = menu_get_item(NULL, 'admin/settings/logging');
+  $content = system_admin_menu_block($item);
+
+  $output = theme('admin_block_content', $content);
+
+  return $output;
+}
 /**
  * Menu callback; display theme configuration for entire site and individual themes.
  */
@@ -2381,3 +2384,14 @@
 
   return $output;
 }
+
+/**
+ * Implementation of hook_cron().
+ *
+ * Remove older rows from flood table
+ */
+function system_cron() {
+  // Cleanup the flood
+  db_query('DELETE FROM {flood} WHERE timestamp < %d', time() - 3600);
+}
+
Index: system/system.install
===================================================================
--- system/system.install	(revision 1132)
+++ system/system.install	(working copy)
@@ -584,21 +584,6 @@
         PRIMARY KEY (vid, type)
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
 
-      db_query("CREATE TABLE {watchdog} (
-        wid int NOT NULL auto_increment,
-        uid int NOT NULL default '0',
-        type varchar(16) NOT NULL default '',
-        message longtext NOT NULL,
-        severity tinyint unsigned NOT NULL default '0',
-        link varchar(255) NOT NULL default '',
-        location text NOT NULL,
-        referer varchar(128) NOT NULL default '',
-        hostname varchar(128) NOT NULL default '',
-        timestamp int NOT NULL default '0',
-        PRIMARY KEY (wid),
-        KEY (type)
-      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
-
       break;
     case 'pgsql':
       /* create unsigned types */
@@ -1052,20 +1037,6 @@
         PRIMARY KEY (vid, type)
       )");
 
-      db_query("CREATE TABLE {watchdog} (
-        wid serial,
-        uid int NOT NULL default '0',
-        type varchar(16) NOT NULL default '',
-        message text NOT NULL,
-        severity smallint_unsigned NOT NULL default '0',
-        link varchar(255) NOT NULL default '',
-        location text NOT NULL default '',
-        referer varchar(128) NOT NULL default '',
-        hostname varchar(128) NOT NULL default '',
-        timestamp int NOT NULL default '0',
-        PRIMARY KEY (wid)
-      )");
-      db_query("CREATE INDEX {watchdog}_type_idx ON {watchdog} (type)");
       break;
   }
 
@@ -3544,6 +3515,17 @@
  */
 
 /**
+ * Change the severity column in the watchdog table to the new values.
+ */
+function system_update_2007() {
+  $ret = array();
+  $ret[] = update_sql("UPDATE {watchdog} SET severity = ". WATCHDOG_NOTICE ." WHERE severity = 0");
+  $ret[] = update_sql("UPDATE {watchdog} SET severity = ". WATCHDOG_WARNING ." WHERE severity = 1");
+  $ret[] = update_sql("UPDATE {watchdog} SET severity = ". WATCHDOG_ERROR ." WHERE severity = 2");
+  return $ret;
+}
+
+/**
  * @} End of "defgroup updates-5.0-to-x.x"
  * The next series of updates should start at 3000.
  */
Index: watchdog/watchdog.module
===================================================================
--- watchdog/watchdog.module	(revision 1132)
+++ watchdog/watchdog.module	(working copy)
@@ -1,251 +0,0 @@
-<?php
-// $Id: watchdog.module,v 1.165.2.1 2007/01/23 19:07:33 dries Exp $
-
-/**
- * @file
- * System monitoring and logging for administrators.
- *
- * The watchdog module monitors your site and keeps a list of
- * recorded events containing usage and performance data, errors,
- * warnings, and similar operational information.
- *
- * @see watchdog().
- */
-
-/**
- * Implementation of hook_help().
- */
-function watchdog_help($section) {
-  switch ($section) {
-    case 'admin/help#watchdog':
-      $output = '<p>'. t('The watchdog module monitors your system, capturing system events in a log to be reviewed by an authorized individual at a later time. This is useful for site administrators who want a quick overview of activities on their site. The logs also record the sequence of events, so it can be useful for debugging site errors.') .'</p>';
-      $output .= '<p>'. t('The watchdog log is simply a list of recorded events containing usage data, performance data, errors, warnings and operational information. Administrators should check the watchdog report on a regular basis to ensure their site is working properly.') .'</p>';
-      $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@watchdog">Watchdog page</a>.', array('@watchdog' => 'http://drupal.org/handbook/modules/watchdog/')) .'</p>';
-      return $output;
-    case 'admin/logs':
-      return '<p>'. t('The watchdog module monitors your web site, capturing system events in a log to be reviewed by an authorized individual at a later time. The watchdog log is simply a list of recorded events containing usage data, performance data, errors, warnings and operational information. It is vital to check the watchdog report on a regular basis as it is often the only way to tell what is going on.') .'</p>';
-  }
-}
-
-/**
- * Implementation of hook_menu().
- */
-function watchdog_menu($may_cache) {
-  $items = array();
-
-  if ($may_cache) {
-    $items[] = array('path' => 'admin/logs/watchdog', 'title' => t('Recent log entries'),
-      'description' => t('View events that have recently been logged.'),
-      'callback' => 'watchdog_overview',
-      'weight' => -1);
-    $items[] = array('path' => 'admin/logs/page-not-found', 'title' => t("Top 'page not found' errors"),
-      'description' => t("View 'page not found' errors (404s)."),
-      'callback' => 'watchdog_top',
-      'callback arguments' => array('page not found'));
-    $items[] = array('path' => 'admin/logs/access-denied', 'title' => t("Top 'access denied' errors"),
-      'description' => t("View 'access denied' errors (403s)."),
-      'callback' => 'watchdog_top',
-      'callback arguments' => array('access denied'));
-    $items[] = array('path' => 'admin/logs/event', 'title' => t('Details'),
-      'callback' => 'watchdog_event',
-      'type' => MENU_CALLBACK);
-  }
-  else {
-    if (arg(0) == 'admin' && arg(1) == 'logs') {
-      // Add the CSS for this module
-      drupal_add_css(drupal_get_path('module', 'watchdog') .'/watchdog.css', 'module', 'all', FALSE);
-    }
-  }
-
-  return $items;
-}
-
-/**
- * Implementation of hook_cron().
- *
- * Remove expired log messages and flood control events.
- */
-function watchdog_cron() {
-  db_query('DELETE FROM {watchdog} WHERE timestamp < %d', time() - variable_get('watchdog_clear', 604800));
-  db_query('DELETE FROM {flood} WHERE timestamp < %d', time() - 3600);
-}
-
-/**
- * Implementation of hook_user().
- */
-function watchdog_user($op, &$edit, &$user) {
-  if ($op == 'delete') {
-    db_query('UPDATE {watchdog} SET uid = 0 WHERE uid = %d', $user->uid);
-  }
-}
-
-function watchdog_form_overview() {
-  $names['all'] = t('all messages');
-  foreach (_watchdog_get_message_types() as $type) {
-    $names[$type] = t('!type messages', array('!type' => t($type)));
-  }
-
-  if (empty($_SESSION['watchdog_overview_filter'])) {
-    $_SESSION['watchdog_overview_filter'] = 'all';
-  }
-
-  $form['filter'] = array(
-    '#type' => 'select',
-    '#title' => t('Filter by message type'),
-    '#options' => $names,
-    '#default_value' => $_SESSION['watchdog_overview_filter']
-  );
-  $form['submit'] = array('#type' => 'submit', '#value' => t('Filter'));
-  $form['#redirect'] = FALSE;
-
-  return $form;
-}
-/**
- * Menu callback; displays a listing of log messages.
- */
-function watchdog_overview() {
-  $icons = array(WATCHDOG_NOTICE  => '',
-                 WATCHDOG_WARNING => theme('image', 'misc/watchdog-warning.png', t('warning'), t('warning')),
-                 WATCHDOG_ERROR   => theme('image', 'misc/watchdog-error.png', t('error'), t('error')));
-  $classes = array(WATCHDOG_NOTICE => 'watchdog-notice', WATCHDOG_WARNING => 'watchdog-warning', WATCHDOG_ERROR => 'watchdog-error');
-
-  $output = drupal_get_form('watchdog_form_overview');
-
-  $header = array(
-    ' ',
-    array('data' => t('Type'), 'field' => 'w.type'),
-    array('data' => t('Date'), 'field' => 'w.wid', 'sort' => 'desc'),
-    array('data' => t('Message'), 'field' => 'w.message'),
-    array('data' => t('User'), 'field' => 'u.name'),
-    array('data' => t('Operations'))
-  );
-
-  $sql = "SELECT w.wid, w.uid, w.severity, w.type, w.timestamp, w.message, w.link, u.name FROM {watchdog} w INNER JOIN {users} u ON w.uid = u.uid";
-  $tablesort = tablesort_sql($header);
-  $type = $_SESSION['watchdog_overview_filter'];
-  if ($type != 'all') {
-    $result = pager_query($sql ." WHERE w.type = '%s'". $tablesort, 50, 0, NULL, $type);
-  }
-  else {
-    $result = pager_query($sql . $tablesort, 50);
-  }
-
-  while ($watchdog = db_fetch_object($result)) {
-    $rows[] = array('data' =>
-      array(
-        // Cells
-        $icons[$watchdog->severity],
-        t($watchdog->type),
-        format_date($watchdog->timestamp, 'small'),
-        l(truncate_utf8($watchdog->message, 56, TRUE, TRUE), 'admin/logs/event/'. $watchdog->wid, array(), NULL, NULL, FALSE, TRUE),
-        theme('username', $watchdog),
-        $watchdog->link,
-      ),
-      // Attributes for tr
-      'class' => "watchdog-". preg_replace('/[^a-z]/i', '-', $watchdog->type) .' '. $classes[$watchdog->severity]
-    );
-  }
-
-  if (!$rows) {
-    $rows[] = array(array('data' => t('No log messages available.'), 'colspan' => 6));
-  }
-
-  $output .= theme('table', $header, $rows);
-  $output .= theme('pager', NULL, 50, 0);
-
-  return $output;
-}
-
-/**
- * Menu callback; generic function to display a page of the most frequent
- * watchdog events of a specified type.
- */
-function watchdog_top($type) {
-
-  $header = array(
-    array('data' => t('Count'), 'field' => 'count', 'sort' => 'desc'),
-    array('data' => t('Message'), 'field' => 'message')
-  );
-
-  $result = pager_query("SELECT COUNT(wid) AS count, message FROM {watchdog} WHERE type = '%s' GROUP BY message ". tablesort_sql($header), 30, 0, "SELECT COUNT(DISTINCT(message)) FROM {watchdog} WHERE type = '%s'", $type);
-
-  while ($watchdog = db_fetch_object($result)) {
-    $rows[] = array($watchdog->count, truncate_utf8($watchdog->message, 56, TRUE, TRUE));
-  }
-
-  if (!$rows) {
-    $rows[] = array(array('data' => t('No log messages available.'), 'colspan' => 2));
-  }
-
-  $output  = theme('table', $header, $rows);
-  $output .= theme('pager', NULL, 30, 0);
-
-  return $output;
-}
-
-function theme_watchdog_form_overview($form) {
-  return '<div class="container-inline">'. drupal_render($form) .'</div>';
-}
-
-function watchdog_form_overview_submit($form_id, $form_values) {
-  $_SESSION['watchdog_overview_filter'] = $form_values['filter'];
-}
-
-/**
- * Menu callback; displays details about a log message.
- */
-function watchdog_event($id) {
-  $severity = array(WATCHDOG_NOTICE => t('notice'), WATCHDOG_WARNING => t('warning'), WATCHDOG_ERROR => t('error'));
-  $output = '';
-  $result = db_query('SELECT w.*, u.name, u.uid FROM {watchdog} w INNER JOIN {users} u ON w.uid = u.uid WHERE w.wid = %d', $id);
-  if ($watchdog = db_fetch_object($result)) {
-    $rows = array(
-      array(
-        array('data' => t('Type'), 'header' => TRUE),
-        t($watchdog->type),
-      ),
-      array(
-        array('data' => t('Date'), 'header' => TRUE),
-        format_date($watchdog->timestamp, 'large'),
-      ),
-      array(
-        array('data' => t('User'), 'header' => TRUE),
-        theme('username', $watchdog),
-      ),
-      array(
-        array('data' => t('Location'), 'header' => TRUE),
-        l($watchdog->location, $watchdog->location),
-      ),
-      array(
-        array('data' => t('Referrer'), 'header' => TRUE),
-        l($watchdog->referer, $watchdog->referer),
-      ),
-      array(
-        array('data' => t('Message'), 'header' => TRUE),
-        $watchdog->message,
-      ),
-      array(
-        array('data' => t('Severity'), 'header' => TRUE),
-        $severity[$watchdog->severity],
-      ),
-      array(
-        array('data' => t('Hostname'), 'header' => TRUE),
-        $watchdog->hostname,
-      ),
-    );
-    $attributes = array('class' => 'watchdog-event');
-    $output = theme('table', array(), $rows, $attributes);
-  }
-  return $output;
-}
-
-function _watchdog_get_message_types() {
-  $types = array();
-
-  $result = db_query('SELECT DISTINCT(type) FROM {watchdog} ORDER BY type');
-  while ($object = db_fetch_object($result)) {
-    $types[] = $object->type;
-  }
-
-  return $types;
-}
Index: watchdog/watchdog.css
===================================================================
--- watchdog/watchdog.css	(revision 1132)
+++ watchdog/watchdog.css	(working copy)
@@ -1,26 +0,0 @@
-/* $Id: watchdog.css,v 1.2 2006/08/21 07:33:26 drumm Exp $ */
-
-tr.watchdog-user {
-  background: #ffd;
-}
-tr.watchdog-user .active {
-  background: #eed;
-}
-tr.watchdog-content {
-  background: #ddf;
-}
-tr.watchdog-content .active {
-  background: #cce;
-}
-tr.watchdog-page-not-found, tr.watchdog-access-denied {
-  background: #dfd;
-}
-tr.watchdog-page-not-found .active, tr.watchdog-access-denied .active {
-  background: #cec;
-}
-tr.watchdog-error {
-  background: #ffc9c9;
-}
-tr.watchdog-error .active {
-  background: #eeb9b9;
-}
Index: watchdog/watchdog.info
===================================================================
--- watchdog/watchdog.info	(revision 1132)
+++ watchdog/watchdog.info	(working copy)
@@ -1,11 +0,0 @@
-; $Id: watchdog.info,v 1.3 2006/11/21 20:55:36 dries Exp $
-name = Watchdog
-description = Logs and records system events.
-package = Core - required
-version = VERSION
-
-; Information added by drupal.org packaging script on 2008-08-14
-version = "5.10"
-project = "drupal"
-datestamp = "1218672307"
-
Index: dblog/dblog.info
===================================================================
--- dblog/dblog.info	(revision 0)
+++ dblog/dblog.info	(revision 0)
@@ -0,0 +1,5 @@
+; $Id$
+name = Database logging
+description = Logs and records system events to the database.
+package = Core - optional
+version = VERSION
Index: dblog/dblog.module
===================================================================
--- dblog/dblog.module	(revision 0)
+++ dblog/dblog.module	(revision 0)
@@ -0,0 +1,331 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * System monitoring and logging for administrators.
+ *
+ * The dblog module monitors your site and keeps a list of
+ * recorded events containing usage and performance data, errors,
+ * warnings, and similar operational information.
+ *
+ * @see watchdog().
+ */
+
+define('DBLOG_ROW_LIMIT',         'dblog_row_limit'); 
+define('DBLOG_ROW_LIMIT_DEFAULT', 5000);
+
+/**
+ * Implementation of hook_help().
+ */
+function dblog_help($section) {
+  switch ($section) {
+    case 'admin/help#dblog':
+      $output = '<p>'. t('The dblog module monitors your system, capturing system events in a log to be reviewed by an authorized individual at a later time. This is useful for site administrators who want a quick overview of activities on their site. The logs also record the sequence of events, so it can be useful for debugging site errors.') .'</p>';
+      $output .= '<p>'. t('The dblog log is simply a list of recorded events containing usage data, performance data, errors, warnings and operational information. Administrators should check the dblog report on a regular basis to ensure their site is working properly.') .'</p>';
+      $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@dblog">Dblog page</a>.', array('@dblog' => 'http://drupal.org/handbook/modules/dblog/')) .'</p>';
+      return $output;
+    case 'admin/logs':
+      return '<p>'. t('The dblog module monitors your website, capturing system events in a log to be reviewed by an authorized individual at a later time. The dblog log is simply a list of recorded events containing usage data, performance data, errors, warnings and operational information. It is vital to check the dblog report on a regular basis as it is often the only way to tell what is going on.') .'</p>';
+  }
+}
+
+/**
+ * Implementation of hook_theme()
+ */
+function dblog_theme() {
+  return array(
+    'dblog_form_overview' => array(
+      'arguments' => array('form' => NULL),
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_menu().
+ */
+function dblog_menu($may_cache) {
+  if(!$may_cache){
+    if (arg(0) == 'admin' && arg(1) == 'logs') {
+      // Add the CSS for this module
+      drupal_add_css(drupal_get_path('module', 'dblog') .'/dblog.css', 'module', 'all', FALSE);
+    }
+  }
+
+  if($may_cache){
+    $items[] = array(
+      'path' => 'admin/settings/logging/dblog',
+      'title' => t('Database logging'),
+      'description' => t('Settings for logging to the Drupal database logs. This is the most common method for small to medium sites on shared hosting. The logs are viewable from the admin pages.'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => array('dblog_admin_settings'),
+    );
+
+    $items[] = array(
+      'path' => 'admin/logs/dblog',
+      'title' => t('Recent log entries'),
+      'description' => t('View events that have recently been logged.'),
+      'callback' => 'dblog_overview',
+      'weight' => -1,
+    );
+    $items[] = array(
+      'path' => 'admin/logs/page-not-found',
+      'title' => t("Top 'page not found' errors"),
+      'description' => t("View 'page not found' errors (404s)."),
+      'callback' => 'dblog_top',
+      'callback arguments' => array('page not found'),
+    );
+    $items[] = array(
+      'path' => 'admin/logs/access-denied',
+      'title' => t("Top 'access denied' errors"),
+      'description' => t("View 'access denied' errors (403s)."),
+      'callback' => 'dblog_top',
+      'callback arguments' => array('access denied'),
+    );
+    $items[] = array(
+      'path' => 'admin/logs/event',
+      'title' => t('Details'),
+      'callback' => 'dblog_event',
+      'callback arguments' => arg(3),
+      'type' => MENU_CALLBACK,
+    );
+    return $items;
+  }
+}
+
+function dblog_admin_settings() {
+  $form[DBLOG_ROW_LIMIT] = array(
+    '#type' => 'select',
+    '#title' => t('Discard log entries above the following row limit'),
+    '#default_value' => variable_get(DBLOG_ROW_LIMIT, DBLOG_ROW_LIMIT_DEFAULT),
+    '#options' => drupal_map_assoc(array(100, 500, 1000, 2500, 5000, 10000, 15000, 20000, 25000, 50000)),
+    '#description' => t('The maximum number of rows to keep in the database log. Older entries will be automatically discarded. Requires crontab.')
+  );
+
+  return system_settings_form($form);
+}
+
+/**
+ * Implementation of hook_cron().
+ *
+ * Remove expired log messages and flood control events.
+ */
+function dblog_cron() {
+  // Cleanup the watchdog table
+  $min = db_result(db_query('SELECT MIN(wid) FROM {watchdog}'));
+  if ($min) {
+    $max = db_result(db_query('SELECT MAX(wid) FROM {watchdog}'));
+    if ($max) {
+      if (($max - $min) > variable_get(DBLOG_ROW_LIMIT, DBLOG_ROW_LIMIT_DEFAULT)) {
+        db_query('DELETE FROM {watchdog} WHERE wid < %d', $max - $min); 
+      }
+    }
+  }
+}
+
+/**
+ * Implementation of hook_user().
+ */
+function dblog_user($op, &$edit, &$user) {
+  if ($op == 'delete') {
+    db_query('UPDATE {watchdog} SET uid = 0 WHERE uid = %d', $user->uid);
+  }
+}
+
+function dblog_form_overview() {
+  $names['all'] = t('all messages');
+  foreach (_dblog_get_message_types() as $type) {
+    $names[$type] = t('!type messages', array('!type' => t($type)));
+  }
+
+  if (empty($_SESSION['dblog_overview_filter'])) {
+    $_SESSION['dblog_overview_filter'] = 'all';
+  }
+
+  $form['filter'] = array(
+    '#type' => 'select',
+    '#title' => t('Filter by message type'),
+    '#options' => $names,
+    '#default_value' => $_SESSION['dblog_overview_filter']
+  );
+  $form['submit'] = array('#type' => 'submit', '#value' => t('Filter'));
+  $form['#redirect'] = FALSE;
+
+  return $form;
+}
+/**
+ * Menu callback; displays a listing of log messages.
+ */
+function dblog_overview() {
+  $rows = array();
+  $icons = array(WATCHDOG_NOTICE  => '',
+                 WATCHDOG_WARNING => theme('image', 'misc/watchdog-warning.png', t('warning'), t('warning')),
+                 WATCHDOG_ERROR   => theme('image', 'misc/watchdog-error.png', t('error'), t('error')));
+  $classes = array(WATCHDOG_NOTICE => 'dblog-notice', WATCHDOG_WARNING => 'dblog-warning', WATCHDOG_ERROR => 'dblog-error');
+
+  $output = drupal_get_form('dblog_form_overview');
+
+  $header = array(
+    ' ',
+    array('data' => t('Type'), 'field' => 'w.type'),
+    array('data' => t('Date'), 'field' => 'w.wid', 'sort' => 'desc'),
+    array('data' => t('Message'), 'field' => 'w.message'),
+    array('data' => t('User'), 'field' => 'u.name'),
+    array('data' => t('Operations'))
+  );
+
+  $sql = "SELECT w.wid, w.uid, w.severity, w.type, w.timestamp, w.message, w.link, u.name FROM {watchdog} w INNER JOIN {users} u ON w.uid = u.uid";
+  $tablesort = tablesort_sql($header);
+  $type = $_SESSION['dblog_overview_filter'];
+  if ($type != 'all') {
+    $result = pager_query($sql ." WHERE w.type = '%s'". $tablesort, 50, 0, NULL, $type);
+  }
+  else {
+    $result = pager_query($sql . $tablesort, 50);
+  }
+
+  while ($dblog = db_fetch_object($result)) {
+    $rows[] = array('data' =>
+      array(
+        // Cells
+        $icons[$dblog->severity],
+        t($dblog->type),
+        format_date($dblog->timestamp, 'small'),
+        l(truncate_utf8($dblog->message, 56, TRUE, TRUE), 'admin/logs/event/'. $dblog->wid, array('html' => TRUE)),
+        theme('username', $dblog),
+        $dblog->link,
+      ),
+      // Attributes for tr
+      'class' => "dblog-". preg_replace('/[^a-z]/i', '-', $dblog->type) .' '. $classes[$dblog->severity]
+    );
+  }
+
+  if (!$rows) {
+    $rows[] = array(array('data' => t('No log messages available.'), 'colspan' => 6));
+  }
+
+  $output .= theme('table', $header, $rows);
+  $output .= theme('pager', NULL, 50, 0);
+
+  return $output;
+}
+
+/**
+ * Menu callback; generic function to display a page of the most frequent
+ * dblog events of a specified type.
+ */
+function dblog_top($type) {
+
+  $header = array(
+    array('data' => t('Count'), 'field' => 'count', 'sort' => 'desc'),
+    array('data' => t('Message'), 'field' => 'message')
+  );
+
+  $result = pager_query("SELECT COUNT(wid) AS count, message FROM {watchdog} WHERE type = '%s' GROUP BY message ". tablesort_sql($header), 30, 0, "SELECT COUNT(DISTINCT(message)) FROM {watchdog} WHERE type = '%s'", $type);
+
+  $rows = array();
+  while ($dblog = db_fetch_object($result)) {
+    $rows[] = array($dblog->count, truncate_utf8($dblog->message, 56, TRUE, TRUE));
+  }
+
+  if (empty($rows)) {
+    $rows[] = array(array('data' => t('No log messages available.'), 'colspan' => 2));
+  }
+
+  $output  = theme('table', $header, $rows);
+  $output .= theme('pager', NULL, 30, 0);
+
+  return $output;
+}
+
+function theme_dblog_form_overview($form) {
+  return '<div class="container-inline">'. drupal_render($form) .'</div>';
+}
+
+function dblog_form_overview_submit($form_id, $form_values) {
+  $_SESSION['dblog_overview_filter'] = $form_values['filter'];
+}
+
+/**
+ * Menu callback; displays details about a log message.
+ */
+function dblog_event($id) {
+  $severity = array(WATCHDOG_NOTICE => t('notice'), WATCHDOG_WARNING => t('warning'), WATCHDOG_ERROR => t('error'));
+  $output = '';
+  $result = db_query('SELECT w.*, u.name, u.uid FROM {watchdog} w INNER JOIN {users} u ON w.uid = u.uid WHERE w.wid = %d', $id);
+  if ($dblog = db_fetch_object($result)) {
+    $rows = array(
+      array(
+        array('data' => t('Type'), 'header' => TRUE),
+        t($dblog->type),
+      ),
+      array(
+        array('data' => t('Date'), 'header' => TRUE),
+        format_date($dblog->timestamp, 'large'),
+      ),
+      array(
+        array('data' => t('User'), 'header' => TRUE),
+        theme('username', $dblog),
+      ),
+      array(
+        array('data' => t('Location'), 'header' => TRUE),
+        l($dblog->location, $dblog->location),
+      ),
+      array(
+        array('data' => t('Referrer'), 'header' => TRUE),
+        l($dblog->referer, $dblog->referer),
+      ),
+      array(
+        array('data' => t('Message'), 'header' => TRUE),
+        $dblog->message,
+      ),
+      array(
+        array('data' => t('Severity'), 'header' => TRUE),
+        $severity[$dblog->severity],
+      ),
+      array(
+        array('data' => t('Hostname'), 'header' => TRUE),
+        $dblog->hostname,
+      ),
+      array(
+        array('data' => t('Operations'), 'header' => TRUE),
+        $dblog->link,
+      ),
+    );
+    $attributes = array('class' => 'dblog-event');
+    $output = theme('table', array(), $rows, $attributes);
+  }
+  return $output;
+}
+
+function _dblog_get_message_types() {
+  $types = array();
+
+  $result = db_query('SELECT DISTINCT(type) FROM {watchdog} ORDER BY type');
+  while ($object = db_fetch_object($result)) {
+    $types[] = $object->type;
+  }
+
+  return $types;
+}
+
+function dblog_watchdog($log = array()) {
+  $current_db = db_set_active();
+  db_query("INSERT INTO {watchdog}
+    (uid, type, message, severity, link, location, referer, hostname, timestamp)
+    VALUES
+    (%d, '%s', '%s', %d, '%s', '%s', '%s', '%s', %d)",
+    $log['user']->uid,
+    $log['type'],
+    $log['message'],
+    $log['severity'],
+    $log['link'],
+    $log['request_uri'],
+    $log['referer'],
+    $log['ip'],
+    $log['timestamp']);
+
+  if ($current_db) {
+    db_set_active($current_db);
+  }
+}
Index: dblog/dblog.install
===================================================================
--- dblog/dblog.install	(revision 0)
+++ dblog/dblog.install	(revision 0)
@@ -0,0 +1,53 @@
+<?php
+// $Id$
+
+/**
+ * Implementation of hook_install().
+ */
+function dblog_install() {
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      db_query("CREATE TABLE {watchdog} (
+        wid int NOT NULL auto_increment,
+        uid int NOT NULL default '0',
+        type varchar(16) NOT NULL default '',
+        message longtext NOT NULL,
+        severity tinyint unsigned NOT NULL default '0',
+        link varchar(255) NOT NULL default '',
+        location text NOT NULL,
+        referer varchar(128) NOT NULL default '',
+        hostname varchar(128) NOT NULL default '',
+        timestamp int NOT NULL default '0',
+        PRIMARY KEY (wid),
+        KEY (type)
+      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
+      break;
+
+    case 'pgsql':
+      db_query("CREATE TABLE {watchdog} (
+        wid serial,
+        uid int NOT NULL default '0',
+        type varchar(16) NOT NULL default '',
+        message text NOT NULL,
+        severity smallint_unsigned NOT NULL default '0',
+        link varchar(255) NOT NULL default '',
+        location text NOT NULL default '',
+        referer varchar(128) NOT NULL default '',
+        hostname varchar(128) NOT NULL default '',
+        timestamp int NOT NULL default '0',
+        PRIMARY KEY (wid)
+      )");
+      db_query("CREATE INDEX {watchdog}_type_idx ON {watchdog} (type)");
+
+
+      break;
+  }
+}
+
+/**
+ * Implementation of hook_uninstall().
+ */
+function dblog_uninstall() {
+  db_query('DROP TABLE {watchdog}');
+}
Index: dblog/dblog.css
===================================================================
--- dblog/dblog.css	(revision 0)
+++ dblog/dblog.css	(revision 0)
@@ -0,0 +1,26 @@
+/* $Id: watchdog.css,v 1.2 2006/08/21 07:33:26 drumm Exp $ */
+
+tr.watchdog-user {
+  background: #ffd;
+}
+tr.watchdog-user .active {
+  background: #eed;
+}
+tr.watchdog-content {
+  background: #ddf;
+}
+tr.watchdog-content .active {
+  background: #cce;
+}
+tr.watchdog-page-not-found, tr.watchdog-access-denied {
+  background: #dfd;
+}
+tr.watchdog-page-not-found .active, tr.watchdog-access-denied .active {
+  background: #cec;
+}
+tr.watchdog-error {
+  background: #ffc9c9;
+}
+tr.watchdog-error .active {
+  background: #eeb9b9;
+}
