Index: CHANGELOG.txt
===================================================================
RCS file: /cvs/drupal/drupal/CHANGELOG.txt,v
retrieving revision 1.185
diff -u -F^f -r1.185 CHANGELOG.txt
--- CHANGELOG.txt	9 Apr 2007 13:58:02 -0000	1.185
+++ CHANGELOG.txt	9 Apr 2007 21:59:41 -0000
@@ -2,6 +2,11 @@
 
 Drupal 6.0, xxxx-xx-xx (development version)
 ----------------------
+- New watchdog as a hook functionality.
+  * New hook_watchdog that can be implemented by any module to route log messages to various destinations.
+  * Expands the severity levels from 3 (Error, Warning, Notice) to the 8 levels defined in RFC 3164.
+  * The watchdog module is now called dblog, and is optional, but enabled by default in the default install profile.
+  * New optional syslog.module now in core.
 - Added theme registry: modules can directly provide .tpl.php files for their themes without having to create theme_ functions.
 - Added versioning support to node terms.
 - Made it easier to theme the forum overview page.
Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.153
diff -u -F^f -r1.153 bootstrap.inc
--- includes/bootstrap.inc	6 Apr 2007 13:27:20 -0000	1.153
+++ includes/bootstrap.inc	9 Apr 2007 21:59:42 -0000
@@ -35,22 +35,17 @@
 define('CACHE_AGGRESSIVE', 2);
 
 /**
- * Indicates a notice-level watchdog event; these are normally notifications
- * of normal system events that have occurred and can usually be safely ignored.
- */
-define('WATCHDOG_NOTICE', 0);
-
-/**
- * Indicates a warning-level watchdog event; this can be triggered by an error
- * in a module that does not impact the overall functionality of the site.
- */
-define('WATCHDOG_WARNING', 1);
-
-/**
- * Indicates an error-level watchdog event; could be indicative of an attempt
- * to compromise the security of the site, or a serious system error.
+ *
+ * Severity levels, as defined in RFC 3164 http://www.faqs.org/rfcs/rfc3164.html
  */
-define('WATCHDOG_ERROR', 2);
+define('WATCHDOG_EMERG',    0); // Emergency: system is unusable
+define('WATCHDOG_ALERT',    1); // Alert: action must be taken immediately
+define('WATCHDOG_CRITICAL', 2); // Critical: critical conditions
+define('WATCHDOG_ERROR',    3); // Error: error conditions
+define('WATCHDOG_WARNING',  4); // Warning: warning conditions
+define('WATCHDOG_NOTICE',   5); // Notice: normal but significant condition
+define('WATCHDOG_INFO',     6); // Informational: informational messages
+define('WATCHDOG_DEBUG',    7); // Debug: debug-level messages
 
 /**
  * First bootstrap phase: initialize configuration.
@@ -649,25 +644,29 @@ function request_uri() {
  * @param $message
  *   The message to store in the log.
  * @param $severity
- *   The severity of the message. One of the following values:
- *   - WATCHDOG_NOTICE
- *   - WATCHDOG_WARNING
- *   - WATCHDOG_ERROR
+ *   The severity of the message, as per RFC 3164
  * @param $link
  *   A link to associate with the message.
  */
 function watchdog($type, $message, $severity = WATCHDOG_NOTICE, $link = NULL) {
   global $user, $base_root;
 
-  $current_db = db_set_active();
-
-  // Note: log the exact, entire absolute URL.
-  $request_uri = $base_root . request_uri();
-
-  db_query("INSERT INTO {watchdog} (uid, type, message, severity, link, location, referer, hostname, timestamp) VALUES (%d, '%s', '%s', %d, '%s', '%s', '%s', '%s', %d)", $user->uid, $type, $message, $severity, $link, $request_uri, referer_uri(), $_SERVER['REMOTE_ADDR'], time());
-
-  if ($current_db) {
-    db_set_active($current_db);
+  // Prepare the fields to be logged
+  $log_message = array(
+    'type'        => $type,
+    'message'     => $message,
+    'severity'    => $severity,
+    'link'        => $link,
+    'user'        => $user,
+    'request_uri' => $base_root . request_uri(),
+    'referer'     => referer_uri(),
+    'ip'          => $_SERVER['REMOTE_ADDR'],
+    'timestamp'   => time(),
+    );
+
+  // Call the logging hooks to log/process the message
+  foreach (module_implements('watchdog', TRUE) as $module) {
+    module_invoke($module, 'watchdog', $log_message);
   }
 }
 
Index: includes/module.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/module.inc,v
retrieving revision 1.98
diff -u -F^f -r1.98 module.inc
--- includes/module.inc	4 Feb 2007 21:20:50 -0000	1.98
+++ includes/module.inc	9 Apr 2007 21:59:42 -0000
@@ -423,5 +423,5 @@ function module_invoke_all() {
  * Array of modules required by core.
  */
 function drupal_required_modules() {
-  return array('block', 'filter', 'node', 'system', 'user', 'watchdog');
+  return array('block', 'filter', 'node', 'system', 'user');
 }
Index: profiles/default/default.profile
===================================================================
RCS file: /cvs/drupal/drupal/profiles/default/default.profile,v
retrieving revision 1.8
diff -u -F^f -r1.8 default.profile
--- profiles/default/default.profile	27 Mar 2007 05:13:54 -0000	1.8
+++ profiles/default/default.profile	9 Apr 2007 21:59:42 -0000
@@ -8,7 +8,7 @@
  *  An array of modules to be enabled.
  */
 function default_profile_modules() {
-  return array('color', 'comment', 'help', 'taxonomy');
+  return array('color', 'comment', 'help', 'taxonomy', 'dblog');
 }
 
 /**
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.463
diff -u -F^f -r1.463 system.module
--- modules/system/system.module	6 Apr 2007 14:31:51 -0000	1.463
+++ modules/system/system.module	9 Apr 2007 21:59:44 -0000
@@ -249,6 +249,11 @@ function system_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('system_error_reporting_settings'),
   );
+  $items['admin/settings/logging'] = array(
+    'title' => t('Logging and alerts'),
+    'description' => t('Settings for logging and alerts modules'),
+    'page callback' => 'system_logging_overview',
+  );
   $items['admin/settings/performance'] = array(
     'title' => t('Performance'),
     'description' => t('Enable or disable page caching for anonymous users, and enable or disable CSS preprocessor.'),
@@ -669,16 +674,6 @@ function system_error_reporting_settings
     '#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);
 }
 
@@ -1953,6 +1948,14 @@ function system_settings_overview() {
   return $output;
 }
 
+function system_logging_overview() {
+  $item = menu_get_item('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.
  */
@@ -2431,3 +2434,14 @@ function theme_system_admin_by_module($m
 
   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: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.88
diff -u -F^f -r1.88 system.install
--- modules/system/system.install	30 Mar 2007 08:47:58 -0000	1.88
+++ modules/system/system.install	9 Apr 2007 21:59:47 -0000
@@ -603,21 +603,6 @@ function system_install() {
         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 */
@@ -1089,20 +1074,6 @@ function system_install() {
         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;
   }
 
@@ -3724,6 +3695,17 @@ function system_update_2006() {
 }
 
 /**
+ * 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 = %d WHERE severity = 0", WATCHDOG_NOTICE);
+  $ret[] = update_sql("UPDATE {watchdog} SET severity = %d WHERE severity = 1", WATCHDOG_WARNING);
+  $ret[] = update_sql("UPDATE {watchdog} SET severity = %d WHERE severity = 2", WATCHDOG_ERROR);
+  return $ret;
+}
+
+/**
  * @} End of "defgroup updates-5.0-to-x.x"
  * The next series of updates should start at 3000.
  */
Index: modules/dblog/dblog.info
===================================================================
RCS file: modules/dblog/dblog.info
diff -N modules/dblog/dblog.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/dblog/dblog.info	9 Apr 2007 21:59:47 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Database logging
+description = Logs and records system events to the database.
+package = Core - optional
+version = VERSION
Index: modules/dblog/dblog.module
===================================================================
RCS file: modules/dblog/dblog.module
diff -N modules/dblog/dblog.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/dblog/dblog.module	9 Apr 2007 21:59:47 -0000
@@ -0,0 +1,324 @@
+<?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() {
+  $items['admin/settings/logging/dblog'] = array(
+    'title' => t('Database logging'),
+    'description' => t('Settings for logging to the Drupal dblog database table.'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('dblog_admin_settings'),
+  );
+
+  $items['admin/logs/dblog'] = array(
+    'title' => t('Recent log entries'),
+    'description' => t('View events that have recently been logged.'),
+    'page callback' => 'dblog_overview',
+    'weight' => -1,
+  );
+  $items['admin/logs/page-not-found'] = array(
+    'title' => t("Top 'page not found' errors"),
+    'description' => t("View 'page not found' errors (404s)."),
+    'page callback' => 'dblog_top',
+    'page arguments' => array('page not found'),
+  );
+  $items['admin/logs/access-denied'] = array(
+      'title' => t("Top 'access denied' errors"),
+    'description' => t("View 'access denied' errors (403s)."),
+    'page callback' => 'dblog_top',
+    'page arguments' => array('access denied'),
+  );
+  $items['admin/logs/event/%'] = array(
+    'title' => t('Details'),
+    'page callback' => 'dblog_event',
+    'page arguments' => array(3),
+    'type' => MENU_CALLBACK,
+  );
+  return $items;
+}
+
+function dblog_init() {
+  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);
+  }
+}
+
+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: modules/dblog/dblog.install
===================================================================
RCS file: modules/dblog/dblog.install
diff -N modules/dblog/dblog.install
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/dblog/dblog.install	9 Apr 2007 21:59:47 -0000
@@ -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: modules/syslog/syslog.info
===================================================================
RCS file: modules/syslog/syslog.info
diff -N modules/syslog/syslog.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/syslog/syslog.info	9 Apr 2007 21:59:47 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Syslog
+description = Logs and records system events to syslog.
+package = Core - optional
+version = VERSION
Index: modules/syslog/syslog.module
===================================================================
RCS file: modules/syslog/syslog.module
diff -N modules/syslog/syslog.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/syslog/syslog.module	9 Apr 2007 21:59:47 -0000
@@ -0,0 +1,93 @@
+<?php
+// $Id$
+
+/**
+ * @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['admin/settings/logging/syslog'] = array(
+    'title'          => t('Syslog'),
+    'description'    => t('Settings for syslog logging.'),
+    'page callback'  => 'drupal_get_form',
+    'page arguments' => array('syslog_admin_settings'),
+  );
+  return $items;
+}
+
+function syslog_admin_settings() {
+  $form[SYSLOG_FACILITY] = array(
+    '#type'          => 'select',
+    '#title'         => t('Syslog facility to send to'),
+    '#default_value' => variable_get(SYSLOG_FACILITY, LOG_LOCAL0),
+    '#options'       => syslog_facility_list(),
+    '#description'   => t('Select the syslog facility to send Drupal\'s messages to. For more information on syslog facilities, 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() {
+  return array(
+    LOG_USER   => t('LOG_USER - User level messages. Use this for Windows.'),
+    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'),
+  );
+}
+
+function syslog_watchdog($log_entry) {
+  static $log_init = FALSE;
+
+  if (!$log_init) {
+    $log_init = TRUE;
+    openlog('drupal', LOG_NDELAY, variable_get(SYSLOG_FACILITY, LOG_LOCAL0));
+  }
+
+  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;
+}
