PHP: Отслеживание ошибок
Программирую на PHP уже много лет, и встречал у своих знакомых программистов практику сокрытия ошибок от заказчиков. Они делали замену стандартного обработчика ошибок на свою функцию, а в ней делали краткую регистрацию ошибки в лог файл или вообще ничего не делали. Может это и полезно в коммерческой практике, но никак не улучшает получаемый код и его надежность. Программный код, как правило, проверяется в стандартных ситуациях, а предусмотреть все нестандартные ситуации заранее невозможно. Очень продуктивно, когда программист занимается не только разработкой программного продукта, но и его поддержкой. Выявление и ликвидация различных программных ошибок не только улучшает уже написанный код, но и позволяет внедрять полученные знания в новые, разрабатываемые скрипты.
Заранее сформулирую, какие именно нужно решить проблемы:
- сделать свой обработчик ошибок,
- обработчик должен регистрировать саму ошибку и ее сопутствующую информацию,
- должно регистрироваться место возникновения ошибки,
- должен определяться вышестоящий путь выполнения PHP скриптов, предшествующий ошибке,
- полученные данные должны добавляться в лог-файл,
- нужно вести не один лог-файл, а несколько (например, в зависимости от даты возникновения ошибки).
Функция обработки ошибок
function MyErrorHandler($errno, $errstr, $errfile, $errline) {
//Код обработчика
return true; //Что бы не был вызван стандартный обработчик ошибок
}
Определение типа ошибки
//Выход, если нестандартная ошибка
if (error_reporting() == 0) return;
//Список типов ошибок
$errorType = array (
E_ERROR => 'ERROR',
E_WARNING => 'WARNING',
E_PARSE => 'PARSING ERROR',
E_NOTICE => 'NOTICE',
E_CORE_ERROR => 'CORE ERROR',
E_CORE_WARNING => 'CORE WARNING',
E_COMPILE_ERROR => 'COMPILE ERROR',
E_COMPILE_WARNING => 'COMPILE WARNING',
E_USER_ERROR => 'USER ERROR',
E_USER_WARNING => 'USER WARNING',
E_USER_NOTICE => 'USER NOTICE',
E_STRICT => 'STRICT NOTICE',
E_RECOVERABLE_ERROR => 'RECOVERABLE ERROR'
);
//Определение типа ошибки
if (array_key_exists($errno, $errorType)) {
$err = $errorType[$errno];
} else {
$err = 'CAUGHT EXCEPTION';
}
Сообщение об ошибке
$errMsg = gmstrftime('%H:%M:%S - ').$err.': '.$errstr.' in '.$errfile.' on line '.$errline;
Traceroute (маршрут ранее выполняемого кода)
$c = 0; //Текущий уровень вложенности кода
$level = 0; //Уровень, выше которого формируется отчет
$backtrace = debug_backtrace(); //Получение списка вызова функций до текущего места
if(count($backtrace)>$level) {
foreach ($backtrace as $track_point) {
if($c>$level) { //Формирование отчета
$errMsg .= "\n".' \---> ';
$errMsg .= isset($track_point['class']) ? $track_point['class'] : '';
$errMsg .= isset($track_point['type']) ? $track_point['type'] : '';
$errMsg .= isset($track_point['function']) ? $track_point['function'].'()' : '';
$errMsg .= isset($track_point['file']) ? ' called at ['.$track_point['file'] : '';
$errMsg .= isset($track_point['line']) ? ' line '.$track_point['line'].']' : '';
}
$c++;
}
}
Вывод данных в файл
$fileName = 'err_'. gmstrftime('%Y_%m_%d.log');
file_put_contents($fileName, $errMsg . "\n", FILE_APPEND);
Замена обработчика ошибки
$old_error_handler = set_error_handler('MyErrorHandler');
Результат тестового запуска
В лог файл err_2010_08_26.log была выведена следующая информация:
10:06:24 - NOTICE: Undefined variable: a in W:\home\my1.ku\www\index.php on line 5
\---> MyFunc3() called at [W:\home\my1.ku\www\index.php line 9]
\---> MyFunc2() called at [W:\home\my1.ku\www\index.php line 13]
\---> MyFunc1() called at [W:\home\my1.ku\www\index.php line 16]
