Watchdog_mail - системные журналы на электронную почту

Аватар пользователя seaji seaji 14 мая 2008 в 18:56

Привет всем!
Вчера случайно натолкнулся на системную функцию watchdog_overview() и решил ее расковырять.
Что делает эта функция? Она подготавливает и выводит список системных сообщений на странице: http://ваш_сайт/admin/logs/watchdog
Я подумал, что было бы клево, если бы этот список системных сообщений отсылался бы мне на электронную почту при ежедневном выполнении заданий крона.
Я давно мечтал о такой функциональности так как сейчас уже у меня семь сайтов, и следить за всеми этими сайтами я просто не могу физически.
Пробовал искать модули, но ничего так и не нашел.
Есть модули для D6, но там уже отдельная тема. В Drupal 6 вы можете назначить для каждого типа события свое уведомление.
Скажем, если это "замечание" - то никаких действий не производится, если это "предупреждение" - высылается письмо, если это "ошибка" - высылается SMS сообщение на ваш номер.
Вот так вот в D6, но до него еще далеко, а работать нужно сейчас.

Итак, что нужно делать для установки.
1. Скачать архив, прикрепленный к этому посту.
2. Этот архив содержит два файла "watchdog_mail.php" и "cron.php"
3. Нужно поменять параметры в начале файла "watchdog_mail.php", там задается отправитель, получатель и тема письма.
4. Закачать эти два файла в корневую папку установки Друпала.
5. Настроить крон и наслаждаться.

Известные проблемы: ни как не получается использовать тег "style" в теле письма для раскрашивания разных типов сообщений.

ВложениеРазмер
Иконка пакета watchdog_mail.zip2.05 КБ

Комментарии

Аватар пользователя seaji seaji 14 мая 2008 в 19:06

Для тех, кому интересен код, но архивы качать лень, вот он:

<?php
/**************************************
* Variables *
**************************************/
$mail_to= 'your-name@example.com'; // Ваш адрес электронной почты
$mail_subject = '['.$_SERVER['HTTP_HOST'].'] report'; // Тема письма '[www.example.com] report'
// $overview_period = time() - 86400;
$last_day = time() - 86400; // Сутки от теперешнего момента.
$overview_period = variable_get('cron_last', $last_day); // период обзора - с последнего запуска крона или за сутки.
$mailkey = 'watchdog_overview_mail';
$headers = array (
'From' => 'name@from.com',
'Reply-To' => 'name@from.com',
'MIME-Version' => '1.0',
'Content-Type' => 'text/html; charset=UTF-8',
'Content-Transfer-Encoding' => 'quoted-printable' );
/**********************************************************
* Override of the system watchdog_overview() function *
**********************************************************/
function watchdog_overview_mail_body($overview_period) {
$output = "\n\n";

$classes = array(WATCHDOG_NOTICE => 'watchdog-notice', WATCHDOG_WARNING => 'watchdog-warning', WATCHDOG_ERROR => 'watchdog-error');
$header = array(
array('data' => t('Type')),
array('data' => t('Date')),
array('data' => t('Message')),
array('data' => t('User')),
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";
$result = db_query($sql ." WHERE w.timestamp > '%d' ORDER BY w.wid desc", $overview_period);

while ($watchdog = db_fetch_object($result)) {
$rows[] = array('data' =>
array(
// Cells
t($watchdog->type),
format_date($watchdog->timestamp, 'small'),
l(truncate_utf8($watchdog->message, 80, TRUE, TRUE), 'http://'.$_SERVER['HTTP_HOST'].'/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],
'style' => 'font-size: 8pt; border: 1px solid #DDDDDD;'
);
}

if (!$rows) {
$rows[] = array(array('data' => t('No log messages available.'), 'colspan' => 5));
}
$output .= format_date(time(), $type = 'large').' '.$_SERVER['HTTP_HOST'].'
';
$output .= '

tr.watchdog-notice td { background-color:#FFFFFF; }
tr.watchdog-warning td { background-color:#FCFDBD; }
tr.watchdog-error td { background-color:#FFDAD2; }
tr.watchdog-cron td { background-color:#D2F4FF; }
tr.watchdog-content td { background-color:#CBCBFA; }
tr.watchdog-user td { background-color:#EFEFDE; }
';
$output .= theme('table', $header, $rows, array('cellpadding' => '2px'));
$output .= '';
return $output;
}

$mail_body .= watchdog_overview_mail_body($overview_period);

// Это место под вопросом с точки зрения того, что лучше использовать imap_8bit() или wordwrap()
$mail_body = imap_8bit($mail_body);
// $mail_body = wordwrap($mail_body, 70);

// Говорят, что письма с незакодированны заголовком считаются потенциально опасными.
// Но реализовывать это я не стал.
// $mail_subject = mb_encode_mimeheader($mail_subject,'UTF-8');

drupal_mail($mailkey, $mail_to, $mail_subject, $mail_body, $from = NULL, $headers);
?>

Аватар пользователя seaji seaji 20 мая 2008 в 14:26

UPD:
В процессе тестов обнаружено три вещи.
1. Цвет строчек разного типа сообщений можно задать с помощью атрибута 'style' элемента 'tr'
2. Запись о работе самого крона не появляется в логах т.к. время этой записи равняется времени отсечки запроса.
3. Дополнительные ссылки типа "просмотреть" и "изменить" имеют относительный вид, что для почтового сообщения - не корректно.

Новая версия, уже с учетом первых двух пунктов.

<?php
/**************************************
* Variables *
**************************************/
$mail_to= 'you_name@example.com'; // Ваш адрес, куда слать письма
$mail_subject = '['.$_SERVER['HTTP_HOST'].'] report'; // Тема письма
$last_day = time() - 86400; // Сутки от теперешнего момента.
$overview_period = variable_get('cron_last', $last_day); // период обзора - с последнего запуска крона или за сутки.
$overview_period = $overview_period - 2; // берем двух секундный запас с момента последнего запуска крона
$mailkey = 'watchdog_overview_mail';
$headers = array (
'From' => 'from@example.com',
'Reply-To' => 'from@example.com',
'MIME-Version' => '1.0',
'Content-Type' => 'text/html; charset=UTF-8',
'Content-Transfer-Encoding' => 'quoted-printable' );

function watchdog_overview_mail_body($overview_period) {
$output = "\n\n"; // \r\n $mail_subject\r\n

$classes = array(WATCHDOG_NOTICE => 'watchdog-notice', WATCHDOG_WARNING => 'watchdog-warning', WATCHDOG_ERROR => 'watchdog-error');
$header = array(
array('data' => 'Тип'),
array('data' => ' Дата/Время '),
array('data' => 'Сообщение'),
array('data' => 'Пользователь'),
array('data' => 'Действия')
);

$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";
$result = db_query($sql ." WHERE w.timestamp > '%d' ORDER BY w.wid desc", $overview_period);

while ($watchdog = db_fetch_object($result)) {
switch ($watchdog->severity) {
case WATCHDOG_NOTICE:
$color = '#D1FFD6'; // цвет замечания
break;
case WATCHDOG_WARNING:
$color = '#FFFFD8'; // цвет предупреждения
break;
case WATCHDOG_ERROR:
$color = '#FFB7B7'; // цвет ошибки
break;
}
switch ($watchdog->type) {
case 'user':
$color = '#EFEFDE'; // цвет для типа "пользователь"
break;
case 'access-denied':
$color = '#FCF2BA'; // цвет для типа "доступ запрещен"
break;
case 'php':
$color = '#EDADAF'; // цвет для типа "PHP"
break;
case 'content':
$color = '#C6CBFF'; // цвет для типа "содержимое"
break;
}
$rows[] = array('data' =>
array(
// Cells
t($watchdog->type),
format_date($watchdog->timestamp, 'small'),
l(truncate_utf8($watchdog->message, 80, TRUE, TRUE), 'http://'.$_SERVER['HTTP_HOST'].'/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],
'style' => 'font-size: 8pt; border: 1px solid #DDDDDD; background-color: '.$color
);
}

if (!$rows) {
$rows[] = array(array('data' => t('No log messages available.'), 'colspan' => 5));
}
$output .= format_date(time(), $type = 'large').' '.$_SERVER['HTTP_HOST'].'">'.$_SERVER['HTTP_HOST'].'
';
$output .= theme('table', $header, $rows, array('cellpadding' => '2px'));
$output .= '';
return $output;
}

$mail_body .= watchdog_overview_mail_body($overview_period);
$mail_body = imap_8bit($mail_body);
// $mail_body = wordwrap($mail_body, 70);

// $mail_subject = mb_encode_mimeheader($mail_subject,'UTF-8');

drupal_mail($mailkey, $mail_to, $mail_subject, $mail_body, $from = NULL, $headers);
?>

Аватар пользователя seaji seaji 5 июня 2008 в 14:21

Еще одно обновление.
В результате тестов этого скрипта выяснилось еще две вещи.
1. Не хорошо сначала высылать письмо, потом отрабатывать крон. Во первых мы узнает отработал или нет крон сегодня только через сутки, во вторых на некоторых моих сайтах крон вообще перестал запускаться. Следовательно тут идет преимущество крона. Он должен быть выполнен первым, а затем уже можно и письмо выслать.
В связи с этим предлагаю включать watchdog_mail.php в конце файла cron.php
<?php
include_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
drupal_cron_run();

include_once 'watchdog_mail.php';
?>
2. Не хорошо высылать письмо при каждом прогоне крона. У меня на одном сайте крон выполняется каждые шесть часов. Соответственно я имею четыре письма в день и в каждом письме максимум три сообщения, а чаще всего - ни одного.
Еще на другом сайте у меня уже третий день крон просто зависает и в каждом новом письме дублируются записи прошлых дней.
Значит нужно ввести новую переменную, в которую фиксировать время отправки письма. Сверяясь с этой переменной можно выбирать события с момента последней отправки письма (а не отработки крона) и ограничить отправку до 1 раза в сутки.
<?php
/**************************************
* Variables *
**************************************/
$mail_to= 'you@example.com';
$mail_subject = '['.$_SERVER['HTTP_HOST'].'] report';
$time = time();
$last_day = $time - 86400; // Сутки от теперешнего момента.
$overview_period = variable_get('last_watchdog_mail', $last_day); // период обзора - с последнего отправленного письма или за сутки.
$overview_period = $overview_period - 2; // Даем отступ в две секунды
$mailkey = 'watchdog_overview_mail';
$headers = array (
'From' => 'name@example.com',
'Reply-To' => 'name@example.com',
'MIME-Version' => '1.0',
'Content-Type' => 'text/html; charset=UTF-8',
'Content-Transfer-Encoding' => 'quoted-printable' );

function watchdog_overview_mail_body($overview_period) {
$output = "\n\n"; // \r\n $mail_subject\r\n

$classes = array(WATCHDOG_NOTICE => 'watchdog-notice', WATCHDOG_WARNING => 'watchdog-warning', WATCHDOG_ERROR => 'watchdog-error');
$header = array(
array('data' => 'Тип'),
array('data' => ' Дата/Время '),
array('data' => 'Сообщение'),
array('data' => 'Пользователь'),
array('data' => 'Действия')
);

$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";
$result = db_query($sql ." WHERE w.timestamp > '%d' ORDER BY w.wid desc", $overview_period);

while ($watchdog = db_fetch_object($result)) {
switch ($watchdog->severity) {
case WATCHDOG_NOTICE:
$color = '#D1FFD6';
break;
case WATCHDOG_WARNING:
$color = '#FFFFD8';
break;
case WATCHDOG_ERROR:
$color = '#FFB7B7';
break;
}
switch ($watchdog->type) {
case 'user':
$color = '#EFEFDE';
break;
case 'access-denied':
$color = '#FCF2BA';
break;
case 'php':
$color = '#EDADAF';
break;
case 'content':
$color = '#C6CBFF';
break;
}
$rows[] = array('data' =>
array(
// Cells
t($watchdog->type),
format_date($watchdog->timestamp, 'small'),
l(truncate_utf8($watchdog->message, 80, TRUE, TRUE), 'http://'.$_SERVER['HTTP_HOST'].'/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],
'style' => 'font-size: 8pt; border: 1px solid #DDDDDD; background-color: '.$color
);
}

if (!$rows) {
$rows[] = array(array('data' => t('No log messages available.'), 'colspan' => 5));
}
$output .= format_date(time(), $type = 'large').' '.$_SERVER['HTTP_HOST'].'
';
$output .= theme('table', $header, $rows, array('cellpadding' => '2px'));
$output .= '';
return $output;
}

$test_time = $time - $overview_period; // Проверка условия для отправки письма только раз в сутки.
if ($test_time>86400) {
$mail_body .= watchdog_overview_mail_body($overview_period);
$mail_body = imap_8bit($mail_body);
// $mail_body = wordwrap($mail_body, 70);
// $mail_subject = mb_encode_mimeheader($mail_subject,'UTF-8');

if (drupal_mail($mailkey, $mail_to, $mail_subject, $mail_body, $from = NULL, $headers)) {
variable_set('last_watchdog_mail', $time);
}
}
?>

Аватар пользователя seaji seaji 8 июня 2008 в 15:06

У меня на одном хостинге не стала работать функция $mail_body = imap_8bit($mail_body);
В этом случае используйте $mail_body = wordwrap($mail_body, 70);

Аватар пользователя seaji seaji 2 августа 2008 в 13:26

Для шестого Друпала есть модули, которые могут слать или письма или СМС для разных типов событий.