用钉钉提醒 Laravel 11 异常:一个简单的实现
受到这篇帖子启发,联想到自己也有 Error Tracking 的需求。我的项目目前只有 laravel.log 日志,不能主动提醒出错。之前调查过 Sentry、Laravel Flare 这样的专业服务,但最终没有使用。受上述帖子的启发,相比完全没有,自己实现一个简陋的解决方案总比没有强。
注册异常报告
- 使用
dispatch()->afterResponse()
可以在当前请求结束之后,再通知钉钉。 - 虽然是 dispatch,但这儿没有队列任务,并不需要队列运行。
// bootstrap/app.php
->withExceptions(function (Exceptions $exceptions) {
if (App::environment('production')) {
$exceptions->report(function (Exception $e) {
// 等当前请求结束后,再发送到钉钉
$message = Dingtalk::message($e);
dispatch(function () use ($message) {
Dingtalk::send($message);
})->afterResponse();
});
}
})
发送消息到钉钉
- 使用钉钉的机器人 API 发送消息
- 消息支持 Markdown 格式
// app/Dingtalk.php
class Dingtalk
{
public static function sendException(Exception $e): void
{
static::send(static::message($e));
}
public static function message(Exception $e): array
{
return [
'msgtype' => 'markdown',
'markdown' => [
'title' => 'Exception️',
'text' => sprintf(
"# Exception: %s\n\n## File\n%s:%d\n\n## Trace\n%s",
$e->getMessage(),
$e->getFile(),
$e->getLine(),
Str::limit($e->getTraceAsString(), 200),
),
],
];
}
public static function send(array $message): void
{
$token = config('services.dingtalk.access_token');
if (!$token) {
throw new Exception('Dingtalk access token is not set');
}
$response = Http::post('https://oapi.dingtalk.com/robot/send?access_token=' . $token, $message);
if ($response->failed()) {
throw new Exception('Dingtalk message failed to send with status ' . $response->status());
}
if ($response->json('errcode') !== 0) {
throw new Exception('Dingtalk message failed to send with error ' . $response->body());
}
}
}
别忘了配置钉钉 Token:
// config/services.php
'dingtalk' => [
'access_token' => env('DINGTALK_ACCESS_TOKEN'),
],
测试效果
运行一个随机命令,比如:
$ php artisan xxx
ERROR Command "xxx" is not defined.
这是得到的结果:
本帖已被设为精华帖!
本帖由 MArtian
于 9个月前 加精
很早之前就已经用上了系统异常,通知钉钉,企业微信。
这里可以考虑使用
UDP
做个专门的队列上报服务。直接嵌在业务底层代码中的话,日后容易形成瓶颈。特别是队列中如果出现报错的话,短时间会有大量的http
请求,造成网络阻塞。sentry
方案是灵活的,解耦的话,可以配置es-filebeat从日志采集,写入日志服务器,然后从日志服务器再发送消息。