Codeigniter 無法記錄終止性錯誤和異常解決辦法
提醒:
- 這裡討論的終止性錯誤指導致php執行失敗的錯誤,例如E_Error,像E_NOTICE、E_WARNING這樣的報錯Codeigniter框架本身可以完美的捕獲,因此不在討論範圍內。
- 本文已Codeigniter 2.2為例,Codeigniter 2.x 都可以使用本文的方案,大家儘管參考。
- 本文的環境是lnmp,Apache同學可做參考。
- 如果你比較著急獲得結果可以直接跳到“解決方案”處。
Codeigniter 2.x錯誤捕獲機制
Codeigniter 2.x非常簡單,通過“set_error_handler”這個函式將整體php執行過程中的錯誤捕獲到框架本身的一個函式中。
Codeigniter 2.2 system/core/CodeIgniter.php line:73
/*
* ------------------------------------------------------
* Define a custom error handler so we can log PHP errors
* ------------------------------------------------------
*/
set_error_handler('_exception_handler');
Codeigniter 2.2 system/core/Common.php line:446
if ( ! function_exists('_exception_handler' ))
{
function _exception_handler($severity, $message, $filepath, $line)
{
// We don't bother with "strict" notices since they tend to fill up
// the log file with excess information that isn't normally very helpful.
if ($severity == E_STRICT)
{
return ;
}
$_error =& load_class('Exceptions', 'core');
// Should we display the error? We'll get the current error_reporting
// level and add its bits with the severity bits to find out.
if (($severity & error_reporting()) == $severity)
{
$_error->show_php_error($severity, $message, $filepath, $line);
}
// Should we log the error? No? We're done...
if (config_item('log_threshold') == 0)
{
return;
}
$_error->log_exception($severity, $message, $filepath, $line);
}
}
然而set_error_handler無法記錄終止性錯誤,這也是Codeigniter無法記錄終止性錯誤的原因,請看php manual上關於這個函式的一個註解。
The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called.
解決方案
通過“register_shutdown_function”和“set_exception_handler”兩個函式分別捕獲終止性錯誤和未捕獲的異常錯誤。
第一步
在system/core/CodeIgniter.php line:73處增加兩行程式碼:
set_exception_handler('_uncatched_exception_handler');
register_shutdown_function('_shutdown_handler');
第二步
在system/core/CodeIgniter.php line:495行新增下面兩個函式:
if ( ! function_exists('_exception_exception_handler'))
{
function _exception_exception_handler($exception)
{
log_message('error', "Exception:" . var_export($exception, true));
}
}
if ( ! function_exists('_shutdown_handler'))
{
function _shutdown_handler()
{
$error = error_get_last();
$fatalErrors = array(
E_ERROR,
E_PARSE,
E_CORE_ERROR,
E_CORE_WARNING,
E_COMPILE_ERROR,
E_COMPILE_WARNING
);
if (isset($error['type']) && in_array($error['type'], $fatalErrors)) {
$err_msg = sprintf('Severity: Error --> %s %s %s %s %s',$error['message'], $error['type'], $error['type'], $error['file'], $error['line']);
log_message('error', $err_msg);
}
}
}
第三步
重啟你的php-fpm,注意:不能以Kill -USR2傳送訊號量的方式重啟。
最好的方式就是直接殺死程序,再重新開啟執行php-fpm程序。