Codeigniter 无法记录终止性错误和异常解决办法并写入log日志

  提醒: 
  这里讨论的终止性错误指导致php执行失败的错误,例如E_Error,像E_NOTICE、E_WARNING这样的报错Codeigniter框架本身可以完美的捕获,因此不在讨论范围内。
  本文主要要说的是, 一些程序上的问题导致程序出现500错误,并捕获错误,记录到log日志中,如下图包含语法错误,和数据库连接导致的500程序中断错误,方便我们查找问题并解决

在这里插入图片描述

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('_error_handler');

Codeigniter 2.2 system/core/Common.php line:446

if ( ! function_exists('_error_handler'))
{
    function _error_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('_exception_handler');
    register_shutdown_function('_shutdown_handler');
  • 1
  • 2

第二步

在system/core/CodeIgniter.php line:495行添加下面两个函数:

if ( ! function_exists('_exception_handler'))
	{
		/**
		 * Exception Handler
		 *
		 * Sends uncaught exceptions to the logger and displays them
		 * only if display_errors is On so that they don't show up in
		 * production environments.
		 *
		 * @param	Exception	$exception
		 * @return	void
		 */
		function _exception_handler($exception)
		{
			$_error =& load_class('Exceptions', 'core');
			$_error->log_exception('error', 'Exception: '.$exception->getMessage(), $exception->getFile(), $exception->getLine());
	
			// Should we display the error?
			if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors'))) //这里还会遵循入口文件中的错误是否显示
			{
				$_error->show_exception($exception);
			}
	
			exit(1); // EXIT_ERROR
		}
	}

	if ( ! function_exists('_shutdown_handler'))
	{
	/**
	 * Shutdown Handler
	 *
	 * This is the shutdown handler that is declared at the top
	 * of CodeIgniter.php. The main reason we use this is to simulate
	 * a complete custom exception handler.
	 *
	 * E_STRICT is purposivly neglected because such events may have
	 * been caught. Duplication or none? None is preferred for now.
	 *
	 * @link	http://insomanic.me.uk/post/229851073/php-trick-catching-fatal-errors-e-error-with-a
	 * @return	void
	 */
	function _shutdown_handler()
	{
		$last_error = error_get_last();
		if (isset($last_error) &&
			($last_error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING)))
		{
            error_reporting(E_ERROR|E_PARSE);   //设置错误级别
			_error_handler($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']);
		}
	}
}

第三步

语法错误造成的程序中断 500错误,也会记录到日志中哦!
打开日志看看吧

记录一下 error_reporting() 函数对应的错误级别

数字 常量 说明
1 E_ERROR 致命错误,脚本执行中断,就是脚本中有不可识别的东西出现
举例: Error:Invalid parameters. Invalid parameter name
2 E_WARNING 部分代码出错,但不影响整体运行
举例: Warning: require_once(E:/include/config_base.php)
4 E_PARSE  字符、变量或结束的地方写规范有误
举例:  Parse error: syntax error, unexpected $end in
 E_NOTICE 一般通知,如变量未定义等
举例:  Notice: Undefined variable: p in E:\web\index.php on line 17
16  E_CORE_ERROR PHP进程在启动时,发生了致命性错误
举例:  暂无
32  E_CORE_WARNING 在PHP启动时警告(非致命性错误)
举例:  暂无
64 E_COMPILE_ERROR 编译时致命性错误
举例:  暂无
128 E_COMPILE_WARNING 编译时警告级错误
举例:  暂无
256 E_USER_ERROR  用户自定义的错误消息
举例:  暂无
512 E_USER_WARNING 用户自定义的警告消息
举例:  暂无
1024 E_USER_NOTICE  用户自定义的提醒消息
举例:  暂无
2047 E_ALL 以上所有的报错信息,但不包括E_STRICT的报错信息
举例:  暂无
2048 E_STRICT 编码标准化警告,允许PHP建议如何修改代码以确保最佳的互操作性向前兼容性。

error_reporting 变量的默认值是 E_ALL & ~E_NOTICE
开发时,最佳的值为: E_ALL | E_STRICT

如果设置为:error_reporting(E_ALL | E_STRICT),则表示记录所有的错误信息
可能会导致网站出现一大堆的错误代码;但是对于程序员来说应该说是一件好事,可以把代码优化到最优; 一些非致命性错误虽然不影响程序的运行,但是会加重PHP的负担.

英文版

1 E_ERROR Fatal run-time errors. Errors that can not be recovered from. Execution of the script is halted
2 E_WARNING Non-fatal run-time errors. Execution of the script is not halted
4 E_PARSE Compile-time parse errors. Parse errors should only be generated by the parser
8 E_NOTICE Run-time notices. The script found something that might be an error, but could also happen when running a script normally
16 E_CORE_ERROR Fatal errors at PHP startup. This is like an E_ERROR in the PHP core
32 E_CORE_WARNING Non-fatal errors at PHP startup. This is like an E_WARNING in the PHP core
64 E_COMPILE_ERROR Fatal compile-time errors. This is like an E_ERROR generated by the Zend Scripting Engine
128 E_COMPILE_WARNING Non-fatal compile-time errors. This is like an E_WARNING generated by the Zend Scripting Engine
256 E_USER_ERROR Fatal user-generated error. This is like an E_ERROR set by the programmer using the PHP function trigger_error()
512 E_USER_WARNING Non-fatal user-generated warning. This is like an E_WARNING set by the programmer using the PHP function trigger_error()
1024 E_USER_NOTICE User-generated notice. This is like an E_NOTICE set by the programmer using the PHP function trigger_error()
2048 E_STRICT Run-time notices. PHP suggest changes to your code to help interoperability and compatibility of the code
4096 E_RECOVERABLE_ERROR Catchable fatal error. This is like an E_ERROR but can be caught by a user defined handle (see also set_error_handler())
8191 E_ALL All errors and warnings, except level E_STRICT (E_STRICT will be part of E_ALL as of PHP 6.0)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章