场景复现
- 客户端:后端接口报错了,我解析数据失败,你看看为啥?
- 服务端:好,我查查log。你把请求参数给我打印出来。
- 客户端:我咋打印?
- 服务端:....我还是自己查log吧
分析
- 不管哪个语言做服务端开发,一定有异常处理和日志。
- 找到一个三方平台,当捕获到异常或者有新的打印日志时回调,推送错误日志给我们。
- 经过一番调研之后,发现钉钉的机器人是个好工作
后端实现以PHP的Laravel为例,其他语言也可以借鉴思路。
修改日志配置
<?php use Monolog\Handler\NullHandler; use Monolog\Handler\StreamHandler; use Monolog\Handler\SyslogUdpHandler; return [ 'default' => env('LOG_CHANNEL', 'stack'), 'channels' => [ 'stack' => [ 'driver' => 'stack', //测试环境除了使用daily保存每天日志到logs/laravel.log,还使用’dingding‘channel 'channels' => env("APP_ENV") == 'test' ? ['daily', 'dingding'] : ['daily'], 'ignore_exceptions' => false, ], //配置钉钉 驱动选择 monolog 'dingding' => [ 'driver' => 'monolog', 'level' => 'error', 'handler' => \App\Handler\DingdingLogHandler::class, //自定义handler ], 'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => 'debug', 'days' => 14, ], . . . ], ];
上面不重要的代码使用3个竖向排列的.省略显示。
自定义Handler
<?php namespace App\Handler; use App\Library\CurlRequest; use App\Library\Utility; use Monolog\Logger; use Monolog\Handler; class DingdingLogHandler extends Handler\AbstractProcessingHandler { private $apiKey; private $channel; public function __construct( $level = Logger::DEBUG, bool $bubble = true ) { parent::__construct($level, $bubble); } protected function write(array $record): void { $this->send($record['formatted']); } protected function send(string $message): void { $microSecond = Utility::getMicroSecond(); $key = "xxxx"; $hashString = hash_hmac("sha256", $microSecond ."\n" . $key, $key, true); $sign = urlencode(base64_encode($hashString)); CurlRequest::post("https://oapi.dingtalk.com/robot/send?access_token=xxxxx×tamp=".$microSecond."&sign=".$sign, [ "msgtype" => "text", "at" => [ "atMobiles" => [ "xxxx", "xxxx" ] ], "text" => [ "content" => $message ] ]); } }
部署上线的效果