bugsnag 默认收不到 codeigniter 错误,因其错误处理封闭:show_error/show_404 直接输出而不抛异常,绕过 php 错误处理器;需手动重写 my_exceptions 并配置全局 error/exception handler 才能全覆盖上报。

CodeIgniter 本身不内置 Bugsnag 集成,必须手动接入;直接 composer require bugsnag/bugsnag 后,若不重写错误处理器或拦截 show_error/show_404,Bugsnag 就收不到任何框架层错误。
为什么 Bugsnag 默认收不到 CodeIgniter 错误
CodeIgniter 的错误流是封闭的:它用 show_error()、show_404() 直接输出 HTML 或 CLI 文本,不抛出异常,也不触发 PHP 的 set_exception_handler 或 set_error_handler。Bugsnag 默认只捕获未处理异常和 PHP 错误(E_ERROR 等),对 CodeIgniter 主动调用的显示函数完全无感。
- 开发环境开
display_errors=1时,错误被show_error()吃掉,Bugsnag 看不见 - 生产环境关了显示,错误进日志但没发到 Bugsnag
-
try/catch里手动Bugsnag::notifyException($e)有效,但仅限你主动 catch 的地方,漏掉框架底层报错(如路由失败、模型加载异常)
在 CodeIgniter 3 中拦截 show_error 和 show_404
最轻量、兼容性最强的方式:在 application/core/MY_Exceptions.php 中继承并覆盖方法,把错误转成异常再通知 Bugsnag。
创建文件 application/core/MY_Exceptions.php:
class MY_Exceptions extends CI_Exceptions
{
public function show_error($heading, $messages, $template = 'error_general', $status_code = 500)
{
// 构造一个可读的错误消息
$msg = is_array($messages) ? implode("
", $messages) : $messages;
$exception = new RuntimeException("[CI Error] {$heading}: {$msg}");
// 发送给 Bugsnag(确保 Bugsnag 已初始化)
if (function_exists('Bugsnag\notifyException')) {
BugsnagBugsnag::notifyException($exception, function ($report) use ($heading, $messages, $status_code) {
$report->setMetaData([
'ci' => [
'type' => 'show_error',
'heading' => $heading,
'status_code' => $status_code,
'messages' => $messages,
]
]);
});
}
// 继续原逻辑(保持页面可见)
parent::show_error($heading, $messages, $template, $status_code);
}
public function show_404($page = '', $log_error = TRUE)
{
$exception = new RuntimeException("[CI 404] Page not found: {$page}");
if (function_exists('Bugsnag\notifyException')) {
BugsnagBugsnag::notifyException($exception, function ($report) use ($page) {
$report->setMetaData(['ci' => ['type' => 'show_404', 'page' => $page]]);
});
}
parent::show_404($page, $log_error);
}
}
- 必须确保
Bugsnag::configure()在MY_Exceptions加载前完成(推荐放在index.php或application/config/autoload.php末尾) - 不要在
show_error里调用exit()或die(),否则 Bugsnag 上报可能被截断 - 该方案不捕获 PHP 解析错误(如语法错)、
require失败等早期错误——那些得靠set_error_handler补充
补全 PHP 原生错误和未捕获异常
在 index.php 顶部(require_once 框架前)加以下代码,覆盖全局错误入口:
// 初始化 Bugsnag(替换 your-api-key)
require_once FCPATH . 'vendor/autoload.php';
BugsnagBugsnag::configure(['apiKey' => 'your-api-key']);
// 捕获所有 PHP 错误(除 E_NOTICE/E_USER_NOTICE 外)
set_error_handler(function ($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
return;
}
if (in_array($severity, [E_NOTICE, E_USER_NOTICE], true)) {
return;
}
BugsnagBugsnag::notifyError($severity, $message, compact('file', 'line'));
});
// 捕获未捕获异常
set_exception_handler(function ($e) {
BugsnagBugsnag::notifyException($e);
});
-
set_error_handler无法捕获E_PARSE、E_COMPILE_ERROR,所以index.php本身的语法错误仍会白屏——必须靠开启display_errors排查 - CodeIgniter 3 的
ENVIRONMENT === 'production'会静默多数错误,但上述 handler 仍会发给 Bugsnag,这是你想要的行为 - 如果用了
ob_start()或输出缓冲,确保 Bugsnag 上报不被缓存阻塞(一般不影响)
注意 Controller 和 Model 中的异常要自己兜底
CodeIgniter 不强制 try/catch,但 Bugsnag 不会自动捕获你业务代码里抛出又没处理的异常——除非它们最终冒泡到顶层被 set_exception_handler 捕获。而实际中,很多异常在控制器里就被 show_error() 吞了。
- 推荐在控制器基类(如
MY_Controller)的__construct()或关键方法里加统一 try/catch - 数据库查询失败(
$this->db->error())这类非异常错误,需显式判断后调用Bugsnag::notifyError() - 避免在
catch里只写log_message()就完事,漏报等于放弃监控
真正难的不是接入 Bugsnag,而是让 CodeIgniter 所有错误路径——从 PHP 解析失败、路由 404、数据库连接断开,到业务逻辑里的 throw new Exception——都经过同一上报通道。这需要同时动框架入口、核心类和业务习惯,缺一不可。











