Pull to refresh

Lagger — обработка ошибок и отладка в PHP с закрытыми глазами

Reading time 6 min
Views 2.2K
image

Впервые этот инструмент был представлен широкой публике в 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)
  • Обработчик сообщений дебага
Есть 7 классов настраиваемых действий:
  • Запись в лог-файл
  • Отправка 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

Всем желающим присоединиться к проекту — очень рад :)
Всем спасибо за конструктивную критику и отзывы!
Tags:
Hubs:
+12
Comments 45
Comments Comments 45

Articles