Commit 70fcf51e authored by Dries's avatar Dries

- Refactored the statistics and watchdog module (views). The most important

  changes are:

  1. Simplified the statistics pages: there are less pages and on the
     remaining pages there is a lot less visual clutter (less columns and
     better presentation).

  2. Reorganized the 'administer - logs' menu: flattened the menu structure
     and removed a number of links.

  3. Improved performance.  Most statistics pages used about 160 slow SQL
     queries which made the statistics pages fairly unusable on my system.
     The new pages use at least 10 times less SQL queries and render much
     faster.  They are actually usable.

  4. There is now a 'track'-tab on node pages, and a second subtrab on the
     user accounts 'track'-tab for people with the 'access statistics'
     permission.  They can be used to resp. track the node and the user.
     This makes the statistics more accessible.

  5. Changed the way watchdog messages are filtered.  This makes it easier
     to introduce new watchdog types.

  6. Reworked the statistics module's permissions.

  7. Less code: 223 insertions(+), 343 deletions(-).

  8. Fixed several glitches: for example, the statistics pages sorted the
     'Name' column by user ID instead of by name.  Unfortunately, it is
     too difficult to backport these to DRUPAL-4-5.

  TODO:

  1. Review the statistics modules help pages.

  2. Help fine-tune the interfaces/views.

  NOTES:

  1. You'll want to run update.php.
parent 76eace31
......@@ -12,6 +12,7 @@ Drupal x.x.x, xxxx-xx-xx
- flood control mechanism:
* added a mechanism to throttle certain operations.
- usability:
* refactored the statistics and log pages.
* refactored the throttle module configuration.
* added a 'add child page' link to book pages.
- multi-site configuration:
......
......@@ -16,7 +16,7 @@
// Check if the last cron run completed
if (variable_get('cron_busy', false)) {
watchdog('warning', t('Last cron run did not complete.'));
watchdog('cron', t('Last cron run did not complete.'));
}
else {
variable_set('cron_busy', true);
......@@ -27,6 +27,6 @@
// Clean up
variable_set('cron_busy', false);
watchdog('regular', t('Cron run completed'));
watchdog('cron', t('Cron run completed'));
?>
......@@ -20,13 +20,15 @@ CREATE TABLE access (
--
CREATE TABLE accesslog (
aid tinyint(10) NOT NULL auto_increment,
title varchar(255) default NULL,
path varchar(255) default NULL,
url varchar(255) default NULL,
hostname varchar(128) default NULL,
uid int(10) unsigned default '0',
timestamp int(11) unsigned NOT NULL default '0',
KEY accesslog_timestamp (timestamp)
KEY accesslog_timestamp (timestamp),
PRIMARY KEY (aid)
) TYPE=MyISAM;
--
......
......@@ -18,12 +18,15 @@ CREATE TABLE access (
--
CREATE TABLE accesslog (
aid SERIAL,
mask varchar(255) NOT NULL default '',
title varchar(255) default NULL,
path varchar(255) default NULL,
url varchar(255) default NULL,
hostname varchar(128) default NULL,
uid integer default '0',
timestamp integer NOT NULL default '0'
timestamp integer NOT NULL default '0',
PRIMARY KEY (aid)
);
CREATE INDEX accesslog_timestamp_idx ON accesslog (timestamp);
......
......@@ -88,7 +88,8 @@
"2004-10-18" => "update_109",
"2004-10-31: first update since Drupal 4.5.0 release" => "update_110",
"2004-11-07" => "update_111",
"2004-11-15" => "update_112"
"2004-11-15" => "update_112",
"2004-11-28" => "update_113"
);
function update_32() {
......@@ -1991,6 +1992,29 @@ function update_112() {
return $ret;
}
function update_113() {
$ret = array();
if ($GLOBALS['db_type'] == 'mysql') {
$ret[] = update_sql('DROP TABLE {accesslog}');
$ret[] = update_sql("CREATE TABLE {accesslog} (
aid tinyint(10) NOT NULL auto_increment,
title varchar(255) default NULL,
path varchar(255) default NULL,
url varchar(255) default NULL,
hostname varchar(128) default NULL,
uid int(10) unsigned default '0',
timestamp int(11) unsigned NOT NULL default '0',
KEY accesslog_timestamp (timestamp),
PRIMARY KEY (aid))");
}
// Flush the menu cache:
cache_clear_all('menu:', TRUE);
return $ret;
}
function update_sql($sql) {
$edit = $_POST["edit"];
$result = db_query($sql);
......
......@@ -166,7 +166,7 @@ function drupal_goto($path = '', $query = NULL, $fragment = NULL) {
*/
function drupal_not_found() {
header('HTTP/1.0 404 Not Found');
watchdog('httpd', t('404 error: %page not found.', array('%page' => '<em>'. db_escape_string($_GET['q']) .'</em>')));
watchdog('page not found', t('%page not found.', array('%page' => '<em>'. db_escape_string($_GET['q']) .'</em>')));
$path = drupal_get_normal_path(variable_get('site_404', ''));
$status = MENU_NOT_FOUND;
......@@ -185,6 +185,7 @@ function drupal_not_found() {
*/
function drupal_access_denied() {
header('HTTP/1.0 403 Forbidden');
watchdog('access denied', t('%page denied access.', array('%page' => '<em>'. db_escape_string($_GET['q']) .'</em>')));
$path = drupal_get_normal_path(variable_get('site_403', ''));
$status = MENU_NOT_FOUND;
......@@ -339,7 +340,7 @@ function error_handler($errno, $message, $filename, $line, $variables) {
$types = array(1 => 'error', 2 => 'warning', 4 => 'parse error', 8 => 'notice', 16 => 'core error', 32 => 'core warning', 64 => 'compile error', 128 => 'compile warning', 256 => 'user error', 512 => 'user warning', 1024 => 'user notice', 2048 => 'strict warning');
$entry = $types[$errno] .': '. $message .' in '. $filename .' on line '. $line .'.';
watchdog('error', t('%error: %message in %file on line %line.', array('%error' => $types[$errno], '%message' => $message, '%file' => $filename, '%line' => $line)));
watchdog('error', t('%message in %file on line %line.', array('%error' => $types[$errno], '%message' => $message, '%file' => $filename, '%line' => $line)));
if (variable_get('error_level', 1) == 1) {
print '<pre>'. $entry .'</pre>';
......
......@@ -388,7 +388,7 @@ function aggregator_refresh($feed) {
cache_clear_all();
watchdog('regular', t('Aggregator: syndicated content from %site.', array('%site' => '<em>'. $feed[title] .'</em>')));
watchdog('status', t('Aggregator: syndicated content from %site.', array('%site' => '<em>'. $feed[title] .'</em>')));
drupal_set_message(t('Syndicated content from %site.', array('%site' => '<em>'. $feed['title'] .'</em>')));
}
break;
......
......@@ -388,7 +388,7 @@ function aggregator_refresh($feed) {
cache_clear_all();
watchdog('regular', t('Aggregator: syndicated content from %site.', array('%site' => '<em>'. $feed[title] .'</em>')));
watchdog('status', t('Aggregator: syndicated content from %site.', array('%site' => '<em>'. $feed[title] .'</em>')));
drupal_set_message(t('Syndicated content from %site.', array('%site' => '<em>'. $feed['title'] .'</em>')));
}
break;
......
......@@ -95,7 +95,7 @@ function drupal_directory_ping($arguments) {
db_query("DELETE FROM {directory} WHERE link = '%s' OR mail = '%s'", $link, $mail);
db_query("INSERT INTO {directory} (link, name, mail, slogan, mission, timestamp) VALUES ('%s', '%s', '%s', '%s', '%s', %d)", $link, $name, $mail, $slogan, $mission, time());
watchdog('regular', t('Directory: ping from %name (%link).', array('%name' => "<em>$name</em>", '%link' => "<em>$link</em>")));
watchdog('drectory ping', t('ping from %name (%link).', array('%name' => "<em>$name</em>", '%link' => "<em>$link</em>")));
return new xmlrpcresp(new xmlrpcval(1, 'int'));
}
......
......@@ -95,7 +95,7 @@ function drupal_directory_ping($arguments) {
db_query("DELETE FROM {directory} WHERE link = '%s' OR mail = '%s'", $link, $mail);
db_query("INSERT INTO {directory} (link, name, mail, slogan, mission, timestamp) VALUES ('%s', '%s', '%s', '%s', '%s', %d)", $link, $name, $mail, $slogan, $mission, time());
watchdog('regular', t('Directory: ping from %name (%link).', array('%name' => "<em>$name</em>", '%link' => "<em>$link</em>")));
watchdog('drectory ping', t('ping from %name (%link).', array('%name' => "<em>$name</em>", '%link' => "<em>$link</em>")));
return new xmlrpcresp(new xmlrpcval(1, 'int'));
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -21,20 +21,6 @@ function watchdog_help($section = 'admin/help#watchdog') {
return t('<p>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 <a href="%watchdog">check the watchdog report</a> on a regular basis as it is often the only way to tell what is going on.</p>', array('%watchdog' => url('admin/logs')));
case 'admin/logs':
return t('<p>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>');
case 'admin/logs/error':
return t('<p>Watchdog events about PHP and database errors.</p>');
case 'admin/logs/httpd':
return t('<p>Watchdog events that are from the web server, like 404s, etc.</p>');
case 'admin/logs/regular':
return t('<p>Watchdog events that are "normal" and have no other classification.</p>');
case 'admin/logs/search':
return t('<p>Watchdog events showing what users have searched for.</p>');
case 'admin/logs/special':
return t('<p>Watchdog events about adding, changing, and moderating nodes and comments.</p>');
case 'admin/logs/user':
return t('<p>Watchdog events that have to do with users and their accounts.</p>');
case 'admin/logs/warning':
return t('<p>Watchdog events that don\'t stop normal operation, but are things you should know.</p>');
case 'admin/modules#description':
return t('Logs and records system events.');
}
......@@ -49,14 +35,9 @@ function watchdog_menu($may_cache) {
if ($may_cache) {
$items[] = array('path' => 'admin/logs', 'title' => t('logs'),
'callback' => 'watchdog_overview', 'access' => user_access('administer watchdog'));
$items[] = array('path' => 'admin/logs/view', 'title' => t('view details'),
'callback' => 'watchdog_view', 'access' => user_access('administer watchdog'),
$items[] = array('path' => 'admin/logs/event', 'title' => t('details'),
'callback' => 'watchdog_event', 'access' => user_access('administer watchdog'),
'type' => MENU_CALLBACK);
foreach (_watchdog_get_message_types() as $type) {
$items[] = array('path' => 'admin/logs/'. $type, 'title' => t($type), 'type' => MENU_DYNAMIC_ITEM);
}
}
return $items;
}
......@@ -81,29 +62,46 @@ function watchdog_cron() {
/**
* Menu callback; displays a listing of log messages.
*/
function watchdog_overview($type = '') {
foreach (_watchdog_get_message_types() as $key) {
$query[$key] = "WHERE type = '". db_escape_string($key) ."'";
function watchdog_overview() {
$names['all'] = t('all messages');
$queries['all'] = '';
foreach (_watchdog_get_message_types() as $type) {
$names[$type] = t('%type messages', array('%type' => $type));
$queries[$type] = "WHERE type = '". db_escape_string($type) ."'";
}
if (empty($_SESSION['watchdog_overview_filter'])) {
$_SESSION['watchdog_overview_filter'] = 'all';
}
$op = $_POST['op'];
if ($op == t('Filter') && isset($_POST['edit']['filter'])) {
$_SESSION['watchdog_overview_filter'] = $_POST['edit']['filter'];
}
$form = form_select(t('Filter by type'), 'filter', $_SESSION['watchdog_overview_filter'], $names);
$form .= form_submit(t('Filter'));
$header = array(
array('data' => t('Type'), 'field' => 'w.type'),
array('data' => t('Date'), 'field' => 'w.timestamp', 'sort' => 'desc'),
array('data' => t('Message'), 'field' => 'w.message'),
array('data' => t('User'), 'field' => 'u.name'),
array('data' => t('Operations'), 'colspan' => '2')
);
$sql = 'SELECT w.*, u.name, u.uid FROM {watchdog} w INNER JOIN {users} u ON w.uid = u.uid '. ($type ? $query[$type] : '') . tablesort_sql($header);
$sql = 'SELECT w.*, u.name, u.uid FROM {watchdog} w INNER JOIN {users} u ON w.uid = u.uid '. $queries[$_SESSION['watchdog_overview_filter']] . tablesort_sql($header);
$result = pager_query($sql, 50);
while ($watchdog = db_fetch_object($result)) {
$rows[] = array('data' =>
array(
// Cells
$watchdog->type,
format_date($watchdog->timestamp, 'small'),
truncate_utf8(strip_tags($watchdog->message), 64),
format_name($watchdog),
$watchdog->link,
l(t('details'), "admin/logs/view/$watchdog->wid")
l(t('details'), "admin/logs/event/$watchdog->wid")
),
// Attributes for tr
'class' => "watchdog-$watchdog->type"
......@@ -118,13 +116,17 @@ function watchdog_overview($type = '') {
if (!empty($pager)) {
$rows[] = array(array('data' => $pager, 'colspan' => '5'));
}
print theme('page', theme('table', $header, $rows));
$output = '<div class="container-inline">'. form($form) .'</div>';
$output .= theme('table', $header, $rows);
print theme('page', $output);
}
/**
* Menu callback; displays details about a log message.
*/
function watchdog_view($id) {
function watchdog_event($id) {
$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)) {
......@@ -132,7 +134,7 @@ function watchdog_view($id) {
$output .= ' <tr><th>'. t('Type') ."</th><td>$watchdog->type</td></tr>";
$output .= ' <tr><th>'. t('Date') .'</th><td>'. format_date($watchdog->timestamp, 'large') .'</td></tr>';
$output .= ' <tr><th>'. t('User') .'</th><td>'. format_name($watchdog) .'</td></tr>';
$output .= ' <tr><th>'. t('Location') ."</th><td>$watchdog->location</td></tr>";
$output .= ' <tr><th>'. t('Location') ."</th><td>". l($watchdog->location, $watchdog->location) ."</td></tr>";
$output .= ' <tr><th>'. t('Message') ."</th><td>$watchdog->message</td></tr>";
$output .= ' <tr><th>'. t('Hostname') ."</th><td>$watchdog->hostname</td></tr>";
$output .= '</table>';
......
......@@ -21,20 +21,6 @@ function watchdog_help($section = 'admin/help#watchdog') {
return t('<p>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 <a href="%watchdog">check the watchdog report</a> on a regular basis as it is often the only way to tell what is going on.</p>', array('%watchdog' => url('admin/logs')));
case 'admin/logs':
return t('<p>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>');
case 'admin/logs/error':
return t('<p>Watchdog events about PHP and database errors.</p>');
case 'admin/logs/httpd':
return t('<p>Watchdog events that are from the web server, like 404s, etc.</p>');
case 'admin/logs/regular':
return t('<p>Watchdog events that are "normal" and have no other classification.</p>');
case 'admin/logs/search':
return t('<p>Watchdog events showing what users have searched for.</p>');
case 'admin/logs/special':
return t('<p>Watchdog events about adding, changing, and moderating nodes and comments.</p>');
case 'admin/logs/user':
return t('<p>Watchdog events that have to do with users and their accounts.</p>');
case 'admin/logs/warning':
return t('<p>Watchdog events that don\'t stop normal operation, but are things you should know.</p>');
case 'admin/modules#description':
return t('Logs and records system events.');
}
......@@ -49,14 +35,9 @@ function watchdog_menu($may_cache) {
if ($may_cache) {
$items[] = array('path' => 'admin/logs', 'title' => t('logs'),
'callback' => 'watchdog_overview', 'access' => user_access('administer watchdog'));
$items[] = array('path' => 'admin/logs/view', 'title' => t('view details'),
'callback' => 'watchdog_view', 'access' => user_access('administer watchdog'),
$items[] = array('path' => 'admin/logs/event', 'title' => t('details'),
'callback' => 'watchdog_event', 'access' => user_access('administer watchdog'),
'type' => MENU_CALLBACK);
foreach (_watchdog_get_message_types() as $type) {
$items[] = array('path' => 'admin/logs/'. $type, 'title' => t($type), 'type' => MENU_DYNAMIC_ITEM);
}
}
return $items;
}
......@@ -81,29 +62,46 @@ function watchdog_cron() {
/**
* Menu callback; displays a listing of log messages.
*/
function watchdog_overview($type = '') {
foreach (_watchdog_get_message_types() as $key) {
$query[$key] = "WHERE type = '". db_escape_string($key) ."'";
function watchdog_overview() {
$names['all'] = t('all messages');
$queries['all'] = '';
foreach (_watchdog_get_message_types() as $type) {
$names[$type] = t('%type messages', array('%type' => $type));
$queries[$type] = "WHERE type = '". db_escape_string($type) ."'";
}
if (empty($_SESSION['watchdog_overview_filter'])) {
$_SESSION['watchdog_overview_filter'] = 'all';
}
$op = $_POST['op'];
if ($op == t('Filter') && isset($_POST['edit']['filter'])) {
$_SESSION['watchdog_overview_filter'] = $_POST['edit']['filter'];
}
$form = form_select(t('Filter by type'), 'filter', $_SESSION['watchdog_overview_filter'], $names);
$form .= form_submit(t('Filter'));
$header = array(
array('data' => t('Type'), 'field' => 'w.type'),
array('data' => t('Date'), 'field' => 'w.timestamp', 'sort' => 'desc'),
array('data' => t('Message'), 'field' => 'w.message'),
array('data' => t('User'), 'field' => 'u.name'),
array('data' => t('Operations'), 'colspan' => '2')
);
$sql = 'SELECT w.*, u.name, u.uid FROM {watchdog} w INNER JOIN {users} u ON w.uid = u.uid '. ($type ? $query[$type] : '') . tablesort_sql($header);
$sql = 'SELECT w.*, u.name, u.uid FROM {watchdog} w INNER JOIN {users} u ON w.uid = u.uid '. $queries[$_SESSION['watchdog_overview_filter']] . tablesort_sql($header);
$result = pager_query($sql, 50);
while ($watchdog = db_fetch_object($result)) {
$rows[] = array('data' =>
array(
// Cells
$watchdog->type,
format_date($watchdog->timestamp, 'small'),
truncate_utf8(strip_tags($watchdog->message), 64),
format_name($watchdog),
$watchdog->link,
l(t('details'), "admin/logs/view/$watchdog->wid")
l(t('details'), "admin/logs/event/$watchdog->wid")
),
// Attributes for tr
'class' => "watchdog-$watchdog->type"
......@@ -118,13 +116,17 @@ function watchdog_overview($type = '') {
if (!empty($pager)) {
$rows[] = array(array('data' => $pager, 'colspan' => '5'));
}
print theme('page', theme('table', $header, $rows));
$output = '<div class="container-inline">'. form($form) .'</div>';
$output .= theme('table', $header, $rows);
print theme('page', $output);
}
/**
* Menu callback; displays details about a log message.
*/
function watchdog_view($id) {
function watchdog_event($id) {
$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)) {
......@@ -132,7 +134,7 @@ function watchdog_view($id) {
$output .= ' <tr><th>'. t('Type') ."</th><td>$watchdog->type</td></tr>";
$output .= ' <tr><th>'. t('Date') .'</th><td>'. format_date($watchdog->timestamp, 'large') .'</td></tr>';
$output .= ' <tr><th>'. t('User') .'</th><td>'. format_name($watchdog) .'</td></tr>';
$output .= ' <tr><th>'. t('Location') ."</th><td>$watchdog->location</td></tr>";
$output .= ' <tr><th>'. t('Location') ."</th><td>". l($watchdog->location, $watchdog->location) ."</td></tr>";
$output .= ' <tr><th>'. t('Message') ."</th><td>$watchdog->message</td></tr>";
$output .= ' <tr><th>'. t('Hostname') ."</th><td>$watchdog->hostname</td></tr>";
$output .= '</table>';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment