因为 hyperf/sentry 仅提供 SDK 注册和捕获入口,不自动监听 Hyperf 异常生命周期(如 ExceptionHandler、协程崩溃、HTTP 超时等),需手动在 ExceptionHandler 中调用 captureException(),并在 beforeStart 钩子中显式 init(),否则 90% 异常不上报。

为什么 hyperf/sentry 不能直接装完就用
因为官方包 hyperf/sentry 只提供了基础的 SDK 注册和异常捕获入口,并不自动监听 Hyperf 的核心异常生命周期(比如 ExceptionHandler、协程上下文崩溃、HTTP 请求超时中断等)。直接 composer require hyperf/sentry 后,90% 的业务异常根本不会上报。
关键点在于:Sentry 需要主动把异常“送出去”,而 Hyperf 默认不会把 Throwable 交到 Sentry 手里。
- 必须手动在自定义
ExceptionHandler中调用Sentry\captureException() - 需额外监听
Hyperf\ExceptionHandler\Event\AfterExceptionHandler事件,覆盖未被捕获的兜底异常 -
hyperf/sentry默认不启用Tracing,性能采样、DB/HTTP 调用链需单独配置中间件和组件
如何让所有 HTTP 异常都进 Sentry(含 404、500、验证失败)
Hyperf 的 ExceptionHandler 是统一出口,但默认只处理“未被 try-catch 捕获”的异常。很多场景(如 ValidationException、NotFoundHttpException)会被框架提前格式化成 JSON 响应,绕过异常处理器。
正确做法是:写一个通用的 ExceptionHandler,并确保它优先级最高、能覆盖所有 Throwable 子类:
use Hyperf\ExceptionHandler\ExceptionHandler;
use Psr\Http\Message\ResponseInterface;
use Sentry\SentrySdk;
class GlobalExceptionHandler extends ExceptionHandler
{
public function handle(Throwable $throwable, ResponseInterface $response): ResponseInterface
{
// 必须先上报,再决定是否继续处理
if (interface_exists('Sentry\SentrySdk')) {
\Sentry\captureException($throwable);
}
// 此处按需返回响应,不影响上报
return $response->withStatus(500)->withBody(...);
}
public function isValid(Throwable $throwable): bool
{
// 返回 true 表示该异常由本 Handler 处理
return true;
}
}
- 在
config/autoload/exceptions.php中注册该 Handler,并设'priority' => PHP_INT_MAX - 不要依赖
hyperf/sentry自带的SentryExceptionHandler—— 它只处理部分异常类型,且不兼容 Hyperf 3.x 的事件机制 - 若用了
hyperf/validation,需额外监听Hyperf\Validation\Event\ValidatorFailed事件,手动上报验证失败详情
hyperf/sentry 的 DSN 配置容易漏掉的两个地方
DSN 不只填在 config/autoload/sentry.php 就完事。Hyperf 的多进程模型会导致子进程(如 Worker、Timer、Task)无法共享主进程的 Sentry 初始化状态。
- 必须在
bin/hyperf.php的beforeStart钩子中显式调用\Sentry\init(),否则 Task 进程中的异常完全不上报 - DSN 若含特殊字符(如
@、/),必须 URL 编码;常见错误是复制 Sentry 控制台给的 DSN 后没处理密码里的@,导致初始化静默失败 - 环境隔离靠
environment字段,但hyperf/sentry默认不读取HYPERF_ENV,需在sentry.php中显式写'environment' => env('APP_ENV', 'dev')
协程中断、超时、Redis 连接断开这类“非 Exception”错误怎么捕获
Sentry 默认只捕获 Throwable,但 Hyperf 里大量错误表现为协程被 kill、RuntimeException 包裹的底层错误(如 Swoole\Coroutine\Channel::pop(): channel is closed)、或 Redis/MySQL 报出的 Connection refused 等无栈异常。
这类问题必须靠主动埋点 + 上下文补全:
- 在
Client类(如RedisFactory、DatabaseFactory)的createClient方法里 wrap 错误,用\Sentry\configureScope()添加标签(如client_type=redis) - 对
go启动的协程,用defer检查Co::getPcid()是否为 0,非零说明协程被强制终止,此时手动captureMessage() - HTTP 客户端超时建议统一用
GuzzleHttp\Middleware::retry,并在 retry 回调里上报重试次数 & 最终失败原因
没有银弹。Sentry 在 Hyperf 里不是插件式集成,而是需要你顺着异常流、协程流、连接流三路分别打点。最常被忽略的是 Task 进程的独立初始化,以及 DSN 中未编码的敏感字符 —— 这两个点一错,监控就形同虚设。











