
Впервые этот инструмент был представлен широкой публике в 2008 году на конференции Highload.ru, после чего был основательно оптимизирован и доработан. О том, что же это за зверь такой и как им удобно пользоваться читаем далее.
Формат статьи
Сперва было желание написать подробное руководство-спецификацию по всему функционалу библиотеки. Потом понял, что намного наглядней и понятней будет привести простые примеры её практического использования, а после вкратце перечислить список основных возможностей. И так…
На пальцах примерах
config.php — все константы вымышлены, любые совпадения случайны. Важно понимать, что константы эти только для примера приведены. В идеале можно вообще без них всё прописывать (см. далее lagger_init.php).
<?php
define('SKIPER_DIR', LOGS_DIR . DIRECTORY_SEPARATOR . 'skip');
define('SKIPER_EXPIRE', 60 * 60 * 24);
define('SKIPER_HASH_TEMPLATE', '{file}{line}');
define('ERRORS_STDOUT', true);
define('ERRORS_STDOUT_TAGS', null);
define('ERRORS_STDOUT_TEMPLATE', '<div><font color="red"><b>{type}:</b> {message}<br /><em>{file} [{line}]</em></font></div>');
define('ERRORS_LOGING', true);
define('ERRORS_LOGING_TAGS', 'warning,fatal');
define('ERRORS_LOGING_FILEPATH', LOGS_DIR . DIRECTORY_SEPARATOR . 'errors_log.htm');
define('ERRORS_LOGING_LIMIT_SIZE', 500000);
define('ERRORS_LOGING_LIMIT_DAYS', 180);
define('ERRORS_LOGING_TEMPLATE', '{date} {time} <a href="http://{host}{uri}">http://{host}{uri}</a><br /><b>{type}</b>: {message|htmlentities}<br />{file} [{line}]<hr />');
define('ERRORS_SMS', false); // TODO: check /library/SmsSender.php before enable it
define('ERRORS_SMS_TAGS', 'warning,fatal');
define('ERRORS_SMS_TO', '79627271169,79218550471');
define('ERRORS_SMS_FROM', 'MyWebSite');
define('ERRORS_SMS_MESSAGE', 'Web site error, check log at {date} {time}');
define('ERRORS_EMAIL', true); // TODO: must be TRUE on production server
define('ERRORS_EMAIL_TAGS', 'warning,fatal');
define('ERRORS_EMAIL_FROM', 'Lagger <lagger@mywebsite.com>');
define('ERRORS_EMAIL_TO', 'Jack Johnson <jack_admin@gmail.com>, mike_developer@gmail.com');
define('ERRORS_EMAIL_SUBJECT', '{type} error in my website');
define('ERRORS_EMAIL_MESSAGE', "Date: {date} {time}\nURL: http://{host}{uri}\nError({type}): {message}\nSource: {file} [{line}]\n\nPOST:\n{post}\n\nSESSION:\n{session}");
define('DEBUG_STDOUT', true);
define('DEBUG_STDOUT_TAGS', 'test,high');
define('DEBUG_STDOUT_TEMPLATE', '<div><font color="green">{message|htmlentities}</font></div>');
define('DEBUG_LOGING', true);
define('DEBUG_LOGING_TAGS', 'sql');
define('DEBUG_LOGING_FILEPATH', LOGS_DIR . DIRECTORY_SEPARATOR . 'debug_sql_log.csv');
define('DEBUG_LOGING_LIMIT_SIZE', 500000);
define('DEBUG_LOGING_LIMIT_DAYS', 7);
define('DEBUG_LOGING_TEMPLATE', "{date} {time};{process_id|csv};{microtime|csv};{tags|csv};{message|trim|csv}\n");
* This source code was highlighted with Source Code Highlighter.
lagger_init.php — непосредственная конфигурация обработчиков Lagger-а. В данном случае из констант конфига, хотя можно и без них.
<?php
/**************************************************************
REGISTER EVENTSPACE VARS
**************************************************************/
$laggerES = new Lagger_Eventspace();
$laggerES->registerReference('host', $_SERVER['HTTP_HOST']);
$laggerES->registerReference('uri', $_SERVER['REQUEST_URI']);
$laggerES->registerReference('post', $_POST);
$laggerES->registerReference('session', $_SESSION); // Session must be already started!
$laggerES->registerCallback('date', 'date', array('Y-m-d'));
$laggerES->registerCallback('time', 'date', array('H:i:s'));
$laggerES->registerCallback('microtime', 'microtime', array(true));
$laggerES->registerVar('session_id', session_id());
$laggerES->registerVar('process_id', substr(md5(mt_rand()), 25));
/**************************************************************
REGISTER EVENTSPACE MODIFIERS
**************************************************************/
function varToStringLine($value) {
return str_replace(array("\r\n", "\r", "\n"), ' ', is_scalar($value) ? $value : var_export($value, 1));
}
$laggerES->registerModifier('line', 'varToStringLine');
function quoteCSV($string) {
return varToStringLine(str_replace(';', '\\;', $string));
}
$laggerES->registerModifier('csv', 'quoteCSV');
/**************************************************************
SKIPER
**************************************************************/
$daylySkiper = new Lagger_Skiper($laggerES, SKIPER_HASH_TEMPLATE, SKIPER_EXPIRE, new Lagger_ExpireList(SKIPER_DIR, '.dayly_skiper'));
/**************************************************************
LAGGER INTERNAL ERRORS AND EXCEPTIONS HANDLING
**************************************************************/
$emailAction = new Lagger_Action_Mail(ERRORS_EMAIL_FROM, ERRORS_EMAIL_TO, ERRORS_EMAIL_SUBJECT, ERRORS_EMAIL_MESSAGE);
$emailAction->setSkiper($daylySkiper, 'errors_email');
Lagger_Handler::addInternalErrorAction($emailAction);
/**************************************************************
DEBUG HANDLER
**************************************************************/
$debug = new Lagger_Handler_Debug($laggerES);
function toDebug($message, $tags = null) {
if (isset($GLOBALS['debug'])) {
$GLOBALS['debug']->handle($message, $tags);
}
}
if (DEBUG_STDOUT) {
// Allows to rewrite DEBUG_STDOUT_TAGS. Try $_GET['__debug'] = 'high' or $_GET['__debug'] = ''
$debugTagger = new Lagger_Tagger('__debug');
$debug->addAction(new Lagger_Action_Print(DEBUG_STDOUT_TEMPLATE), DEBUG_STDOUT_TAGS, $debugTagger);
$debug->addAction(new Lagger_Action_FirePhp('{message}', '{tags}', FirePHP::INFO), DEBUG_STDOUT_TAGS, $debugTagger);
}
if (DEBUG_LOGING) {
$debug->addAction(new Lagger_Action_FileLog(DEBUG_LOGING_TEMPLATE, DEBUG_LOGING_FILEPATH, DEBUG_LOGING_LIMIT_SIZE, DEBUG_LOGING_LIMIT_DAYS), DEBUG_LOGING_TAGS);
}
// Just for fun in windows servers it will speak the text :)
if(stristr(PHP_OS, 'win') !== false) {
$debug->addAction(new Lagger_Action_WinSpeak('{message}', 100), 'speak');
}
/**************************************************************
ERRORS AND EXCEPTIONS HANDLERS
**************************************************************/
$errors = new Lagger_Handler_Errors($laggerES);
$exceptions = new Lagger_Handler_Exceptions($laggerES);
if (ERRORS_STDOUT) {
$printAction = new Lagger_Action_Print(ERRORS_STDOUT_TEMPLATE, false);
$errors->addAction($printAction);
$exceptions->addAction($printAction);
$errorsFirePhpAction = new Lagger_Action_FirePhp('{message} {file} [{line}]', '{type}', FirePHP::ERROR);
$errors->addAction($errorsFirePhpAction);
$exceptions->addAction($errorsFirePhpAction);
}
if (ERRORS_LOGING) {
$logAction = new Lagger_Action_FileLog(ERRORS_LOGING_TEMPLATE, ERRORS_LOGING_FILEPATH, ERRORS_LOGING_LIMIT_SIZE, ERRORS_LOGING_LIMIT_DAYS);
$errors->addAction($logAction, ERRORS_LOGING_TAGS);
$exceptions->addAction($logAction, ERRORS_LOGING_TAGS);
}
if (ERRORS_SMS) {
$smsAction = new Lagger_Action_Sms(ERRORS_SMS_FROM, ERRORS_SMS_TO, ERRORS_SMS_MESSAGE, true);
$smsAction->setSkiper($daylySkiper, 'errors_sms');
$errors->addAction($smsAction, ERRORS_SMS_TAGS);
$exceptions->addAction($smsAction, ERRORS_SMS_TAGS);
}
if (ERRORS_EMAIL) {
$errors->addAction($emailAction, ERRORS_EMAIL_TAGS);
$exceptions->addAction($emailAction, ERRORS_EMAIL_TAGS);
}
Т.е.
Есть 3 класса обработчиков событий:
- Обработчик системных ошибок PHP всех уровней (в том числе E_FATAL & E_COMPILE)
- Обработчик PHP-исключений (Exceptions)
- Обработчик сообщений дебага
- Запись в лог-файл
- Отправка Email
- Отправка SMS
- Вывод на экран
- Вывод в консоль и popup-уведомления Google Chrome через расширение PHP Console
- Вывод в панель FirePHP
- Генерация исключения (Exception)
- Озвучивание текста события голосом Sam-а из Microsoft :) Windows only
- Игнорирование повторной обработки событий (Lagger_Skiper)
- Мини-шаблонизатор c возможностью расширения списка переменных событий (не пугаться! он очень лёгкий!)
- Теггирование событий и настройка действий на срабатывание по определённым тегам
- Динамическое переопределение тегов срабатывания действий через GET (Lagger_Tagger)
- Обработка внутренних ошибок
- Всего 20kb лаконичного PHP5 кода (100% ООП)
100% Open Source
Скачать последнюю версию
Примеры вместо документации
SVN/trunk
Страница проекта на Google Code
Всем желающим присоединиться к проекту — очень рад :)
Всем спасибо за конструктивную критику и отзывы!