如何从标记为monolog.processor的服务中获取Symfony路由参数
解决方案
你对问题原因的判断正确:Monolog处理器默认的执行时机早于Symfony路由解析流程,负责解析路由并将参数写入Request attributes的RouterListener内核监听器优先级为32,早于多数处理器触发时机,所以直接取值时路由参数还未写入。
以下是两种可行的解决方法:
方案1:绑定低优先级kernel.request事件预存路由参数(最稳妥)
该方案可以保证只要路由解析完成,参数就会提前存入处理器,所有后续日志都能稳定拿到用户ID:
第一步:改造UserProcessor代码
// src/Services/UserProcessor.php use Monolog\Processor\ProcessorInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Event\RequestEvent; final class UserProcessor implements ProcessorInterface { private RequestStack $requestStack; private ?string $userId = null; public function __construct(RequestStack $requestStack) { $this->requestStack = $requestStack; } // 监听kernel.request事件的回调,路由解析完成后执行 public function onKernelRequest(RequestEvent $event): void { if (!$event->isMasterRequest()) { return; } $request = $event->getRequest(); // 从路由参数中取userid,不存在则留空 if ($request->attributes->has('userid')) { $this->userId = $request->attributes->get('userid'); } } public function __invoke(array $record): array { // 只有存在userId的时候才追加到日志上下文 if ($this->userId !== null) { $record['extra']['user_id'] = $this->userId; } return $record; } }
第二步:调整服务配置
在config/services.yaml中给服务同时加处理器和事件监听器标签,设置事件监听器优先级低于32,保证路由解析完成后再执行:
services: App\Services\UserProcessor: arguments: $requestStack: '@request_stack' tags: - { name: monolog.processor } - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 0 }
方案2:直接在处理器中做兼容判断(适合轻量场景)
如果你的日志只会在路由解析完成后触发,也可以直接在__invoke方法中做多层非空判断,避免报错:
public function __invoke(array $record): array { $request = $this->requestStack->getMasterRequest(); if (null !== $request && $request->attributes->has('userid')) { $record['extra']['user_id'] = $request->attributes->get('userid'); } return $record; }
注意:该方案下,路由解析完成前触发的日志(比如内核启动阶段的debug日志)仍然拿不到userid,业务接口请求阶段的日志不受影响。
额外注意事项
- 要兼容CLI命令行场景,CLI下没有HTTP请求,
getMasterRequest()会返回null,一定要做非空判断避免报错 - Symfony 5+以上版本
getMasterRequest()已废弃,替换为getMainRequest()即可
内容的提问来源于stack exchange,提问作者smarber
相关产品推荐
相关产品推荐

