最近在整理项目中的日志问题,查了一些关于 “CI 框架中的日志处理 以及 404异常处理” 的东西,顺便记录一下:
关于错误日志:
1. 在CI框架中的 system/core/CodeIgniter.php 中注册了处理函数(这个是PHP7之后的异常处理机制:可以使用set_error_handler来注册自己的错误处理方法来代替php的标准错误处理方式)
详见:https://blog.csdn.net/zhang197093/article/details/75094816
set_error_handler('_error_handler'); //注册error处理函数 set_exception_handler('_exception_handler'); //注册异常处理函数 register_shutdown_function('_shutdown_handler');
2. 在CI框架的index.php 中引入了init.php
3. 在init.php 中自定义error处理句柄:_error_handler
if ( ! function_exists('_error_handler')) { function _error_handler($level, $msg, $file, $line) { switch ($level) { case E_NOTICE: case E_USER_NOTICE: $error_type = 'Notice'; break; case E_WARNING: case E_USER_WARNING: $error_type = 'Warning'; break; case E_ERROR: $error_type = 'Fatal Error'; break; case E_USER_ERROR: $error_type = 'User Fatal Error'; break; default: $error_type = 'Unknown'; break; } if('Unknown' == $error_type) { return true; } $log = & load_class('Log', 'core'); $log_info = [ 'error_type=' . $error_type, 'error_msg=' . $msg, ]; $log_info_str = implode('||', $log_info); $log->fatal(['%s', $log_info_str]); } }
P.S. 如果是E_ERROR,E_PARSE之类的错误,是不能被用户自定义句柄自动捕获处理的
但是在PHP7 之后,可以在程序的 try-catch 中捕获然后处理,不捕获的话,仍然会按照系统默认的方式处理
关于404异常处理
1. 在CI框架的 application/core/Exception.php 中改写了system/core/Exception.php中的方法,包括show_404方法
public function show_404($page = '', $log_error = TRUE) { // By default we log this, but allow a dev to skip it if ($log_error) { log_message('error', $page); } echo json_encode([ 'errno' => 1, 'errmsg' => 'show404', ]); exit(4); // EXIT_UNKNOWN_FILE }
2. show_404方法中用到的 log_message 方法在 system/core/commen.php 中,系统方法
其中调用/core/Log.php 中的 write_log 方法打印日志
if ( ! function_exists('log_message')) { /** * Error Logging Interface * * We use this as a simple mechanism to access the logging * class and send messages to be logged. * * @param string the error level: 'error', 'debug' or 'info' * @param string the error message * @return void */ function log_message($level, $message) { static $_log; if ($_log === NULL) { // references cannot be directly assigned to static variables, so we use an array $_log[0] =& load_class('Log', 'core'); } $_log[0]->write_log($level, $message); } }
3. 在 application/core/log.php 中 重载了 system/core/Log.php 中的系统方法,所以2中用到的是 application/core/log.php中的 write_log
public function write_log($level = 'error', $msg = '', $php_error = FALSE) { if ($this->_enabled === FALSE) { return FALSE; } $level = strtoupper($level); //将原日志系统映射到现有日志系统中,屏蔽原日志系统 if (isset($this->_levels[$level])) { $this->__log__($this->_levels[$level], array($msg)); $this->flush(); return TRUE; } return FALSE; }
4. 在system/core/CodeIgniter.php中调用了show_404 方法
if ($e404) { if ( ! empty($RTR->routes['404_override'])) { if (sscanf($RTR->routes['404_override'], '%[^/]/%s', $error_class, $error_method) !== 2) { $error_method = 'index'; } $error_class = ucfirst($error_class); if ( ! class_exists($error_class, FALSE)) { if (file_exists(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php')) { require_once(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php'); $e404 = ! class_exists($error_class, FALSE); } // Were we in a directory? If so, check for a global override elseif ( ! empty($RTR->directory) && file_exists(APPPATH.'controllers/'.$error_class.'.php')) { require_once(APPPATH.'controllers/'.$error_class.'.php'); if (($e404 = ! class_exists($error_class, FALSE)) === FALSE) { $RTR->directory = ''; } } } else { $e404 = FALSE; } } // Did we reset the $e404 flag? If so, set the rsegments, starting from index 1 if ( ! $e404) { $class = $error_class; $method = $error_method; $URI->rsegments = array( 1 => $class, 2 => $method ); } else { show_404($RTR->directory.$class.'/'.$method); } }