在记录业务日志时, 我们经常需要为每一条日志都补充上类似 RequestId 类的唯一标识串, 方便后期快速的将某请求的相关的日志流 聚合 查询出来. 首先, RequestId 是要单例贯穿整个请求生命周期的, 如果在整个请求处理过程中, 包括不同的服务层, 模块, 我都需要将 RequestId 透传或作为参数显示的传入 logger 中, 那代码简直不要太美观.
Monolog 作为最为流行的 PHP 日志组件, 如果可以实现为每一条日志自动填充 RequestId, 那使用起来是非常舒服的.
Monolog 的 pushProcessor 方法可以方便我们实现这一需求, pushProcessor 中的 processor 会对你记录的每一条日志进行处理并返回.
在请求的初始阶段, 为本次请求生成一个全局的 RequestId, 我是放在 Request 对象上, 不同框架获取请求会话的 Request 单例对象的方法可能不同, 大家理解就好. 或者你可以单独使用一个单例对象去维护 RequestId, 只要保证对当前请求是单例模式 (放在 DI Container 中最好).
- <?PHP
- use Monolog\Logger;
- use Monolog\Handler\RotatingFileHandler::class;
- use Monolog\Formatter\LineFormatter::class;
- class Log
- $logger = new Logger('default');
- // 添加处理器
- $rfHandler = new RotatingFileHandler(__DIR__ . '/app_default.log', Logger::DEBUG);
- $format = "[%datetime%] %channel%.%level_name%: %extra% %message% %context%\n";
- $dateFormat = 'Y-m-d H:i:s';
- $lFormatter = new LineFormatter($format, $dateFormat, true);
- $rfHandler->setFormatter($lFormatter)
- $logger->pushHandler($rfHandler);
- // 就是在这里做处理啦 $request->getRequestId 自己去实现
- $logger->pushProcessor(function ($log) {
- /** @var Request $request */
- $request = \request();//webman 的
- $log['extra']['request-id'] = $request->getRequestId();
- return $log;
- });
- <?PHP
- // 现在你就可以用日志服务了
- $logger->info('this is monolog example');
- $logger->info('this is log will auto fill requestId');
记得把 RequestId 返回给前端, 这样问题反馈就容易追踪请求链路了.
来源: https://segmentfault.com/a/1190000040056481