最近线上项目最近偶尔报500错误,虽然根据日志可以拿到引发错误的请求参数,但是还是要自己去模拟请求,更甚着,由于等到自己去模拟请求的时候,引发错误的主体(比如,同样的订单,同样的请求参数,订单状态为3时会报错,但是当你去模拟的时候,订单状态已经变为4了,此时又不会报错了)的状态已经发生变化,因此需要保存发生错误时候的上下文。
于是查到CI有一个钩子的功能
最终有pre_system钩子能满足需求:
pre_system 在系统执行的早期调用,这个时候只有 基准测试类 和 钩子类 被加载了, 还没有执行到路由或其他的流程。
具体使用方法如下:
在对应项目的hooks.php里添加
$hook['pre_system'][] = array(
'class' => 'ErrorCatch',
'function' => 'errorCatchInit',
'filename' => 'ErrorCatch.php',
'filepath' => 'controllers/app', //这里不要加APPPATH
);
然后新建对应的类
最终错误处理类如下:
class ErrorCatch {
public function errorCatchInit() {
register_shutdown_function([$this, 'handleShutdown']);
}
public static function handleShutdown() {
//write_log();
}
}
但此时还不能捕获错误日志,因为CI本身自己实现了一套register_shutdown_function,在core/Common.php
的_error_handler
方法里,有如下代码
$is_error = (((E_ERROR | E_PARSE | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR) & $severity) === $severity);
·
·
·
if ($is_error)
{
exit; //直接就脚本退出了
}
有多个register_shutdown_function callback时,当前面的exit后,就不会触发后面的callback了, 于是:
在index.php里添加
define('SELF_ERROR_SHUT_DOWN', 1);
然后
if ($is_error)
{
exit; //直接就脚本退出了
}
改为
if ($is_error)
{
if (defined('SELF_ERROR_SHUT_DOWN')) {
return;
}
exit;
}
至此,就可以统一收集程序错误,并且上报了