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

祝你好运:)

你可能感兴趣的:(PHP)