1. 程式人生 > >Codeigniter 無法記錄終止性錯誤和異常解決辦法

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程序。

祝你好運:)