sentry文档:https://docs.sentry.io/在熟悉了hyperf架构的异常捕获机制后,感觉异常捕获机制中可以非常合理的使用sentry。首先安装sentry:composerrequiresentry/sdk:2.0.3安装完成后添加Sentry\init(\['dsn'=>'yourdsn']);在hyperf.php文件中的App\Exception\Handle\AppExceptionHandle中使用Sentry;publicfunctionhandle(Throwable$throwable,ResponseInterface$response){Sentry\captureException($throwable);return$response->withStatus(500)->withBody(newSwooleStream('InternalServerError.'));}这个时候异常被捕获,发现哨兵服务器没有收到异常。查看源码发现sentry的发送机制是一个请求完成后清空信息队列,而hyperf是基于swoole架构的。一个请求后,进程不会被释放,因此哨兵服务器无法接收数据。Sentry\Transport\HttpTransport构造方法中的第三个参数解释为:该标志控制是否延迟发送事件直到应用程序关闭。默认为真。Sentry不会在推送异常后立即将异常推送给服务器。相反,它将等到进程结束后再发送异常。sentry\ClientBuilder->createTransportInstance方法中init方法创建的HttpTransport的第三个参数为true,改成false重新捕获异常即可接收到请求。但是这个时候,又出现了一个问题。Sentry的推送机制使用的是curl库,而swoole不支持curl协程,这意味着如果生产环境同时出现大量异常,会导致进程阻塞,hyperf的性能会很差严重退化。异步处理刻不容缓!再次查看文档,curlpush是通过Transport类处理的,默认的Transport是HttpTransport,是一种同步推送机制。它还提供异步传输和spoolTransport。删除hyperf.php的Sentryinit方法,在App\Exception\Handle\AppExceptionHandle中修改如下Spool\MemorySpool;useHttp\Discovery\HttpAsyncClientDiscovery;useHttp\Discovery\MessageFactoryDiscovery;useSentry\Options;publicfunctionhandle(Throwable$throwable,ResponseInterface$response){//这里为了方便,每次调用都会重新初始化异常被捕获相关对象应该保存在全局单例中$options=['dsn'=>'https://@sentry.io/'\];$optionObj=新选项($options);$spool=newMemorySpool();$transport=newSpoolTransport($spool);$httpTransport=newHttpTransport($optionObj,HttpAsyncClientDiscovery::find(),MessageFactoryDiscovery::find());$builder=ClientBuilder::create($options);$builder->setTransport($transport);Hub::getCurrent()->bindClient($builder->getClient());中心::getCurrent()->captureException($throwable);//调用这个方法会开始清空之前捕获异常的队列。想了想还是在定时任务中定时清空队列比较合理。$spool->flushQueue($httpTransport);}开始捕获异常,为什么哨兵服务器没有收到请求而留下眼泪没有技术。检查问题后发现是因为HttpAsyncClientDiscovery::find()创建的异步httpTransport的url配置问题。仔细阅读源码,发现可以使用ClientBuilder->createTransportInstance方法。默认方法是private,可以改成public。用它来创建一个transport对象(ps如果可以,可以自己仿写一个,不用修改源码)。修改后代码如下App\Exception\Handle\AppExceptionHandle如下所示useSentry\ClientBuilder;useSentry\Transport\SpoolTransport;useSentry\State\Hub;useSentry\Spool\MemorySpool;publicfunctionhandle(Throwable$throwable,ResponseInterface$response){//为了方便每次捕获异常时重新初始化相关对象,应该保存为全局单例$options=['dsn'=>'https://@sentry.io/<项目>'\];$spool=newMemorySpool();$transport=newSpoolTransport($spool);$builder=ClientBuilder::create($options);$httpTransport=$builder->createTransportInstance();$builder->setTransport($transport);Hub::getCurrent()->bindClient($builder->getClient());Hub::getCurrent()->captureException($throwable);//调用这个方法会开始清空之前捕获异常的队列。想了想还是在定时任务中定时清空队列比较合理。$spool->flushQueue($httpTransport);}捕获异常,哨兵服务器收到异常。这里$spool->flushQueue($httpTransport);会主动推送捕获到的队列异常。想了想还是在定时任务中定时清空队列比较合理。