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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章