CI 配合 register_shutdown_function 统一上报错误日志

最近线上项目最近偶尔报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;
}

至此,就可以统一收集程序错误,并且上报了

原文

你可能感兴趣的:(php,ci)