symfony 6日志需手动配置channels和handlers,否则所有日志混入main通道;必须在monolog.yaml声明channels并严格匹配handler的channels字段,通过服务id、标签注入或别名获取指定通道loggerinterface。

Symfony 6 的日志系统默认启用且开箱可用,但**不配置 channels 和 handlers 就直接用 LoggerInterface 注入,所有日志都会走默认 main 处理器,混在一起难排查**。真正要用好,得动手配通道、绑处理器、选级别。
怎么声明和绑定自定义日志通道
通道不是“写代码时随便起个名就能用”的——必须先在配置里声明,再绑定处理器,否则容器里根本找不到对应服务。
- 在
config/packages/monolog.yaml的顶层加channels列表,比如:channels: ['payment', 'api', 'security']
,漏写就注入失败 - 每个通道需至少一个
handler,且该 handler 的channels字段必须严格匹配,大小写、引号、中括号都不能错:payment_handler: type: stream path: "%kernel.logs_dir%/payment.log" level: info channels: [payment]
- 已有默认通道(
app、doctrine、event)可直接用,不用重复声明 - 别在
config/packages/prod/monolog.yaml里覆盖整个配置——它会完全替代主配置,导致 dev 环境的consolehandler 消失
怎么在代码里拿到指定通道的日志器
三种方式都能用,但行为不同:直取 ID 最灵活,标签注入最省心,别名依赖最直观。
- 服务容器直取:
$this->get('monolog.logger.payment'),适合临时调试或 legacy 控制器 - 标签自动注入:在
config/services.yaml里给服务加{ name: monolog.logger, channel: payment },构造函数类型提示LoggerInterface $logger就自动注入对应通道 - 依赖注入别名:
monolog.logger.payment是 Symfony 自动生成的服务 ID,可直接在构造函数中声明:public function __construct(private LoggerInterface $paymentLogger) {},前提是没被其他配置覆盖 - 运行
bin/console debug:container --tag=monolog.logger可确认所有已注册通道日志器,避免拼错名字
怎么控制日志输出位置和级别
Handler 的 type 和 level 决定日志去哪、记什么,选错会导致关键信息丢失或磁盘爆满。
-
type: stream写文件,path必须可写,推荐用%kernel.logs_dir%/xxx.log;type: rotating_file自动按天/大小轮转,生产环境更稳妥 -
level是“最低记录级别”,设成error就不会记info或warning——别设太高,否则调试时看不到上下文 -
consolehandler 在 dev 环境很有用,但要关掉process_psr_3_messages: false,否则颜色和格式会乱 - 用
fingers_crossedhandler 可延迟写入:只在出现 error 时才把之前 debug/info 日志一并刷到文件,节省 I/O,但内存占用略高
最易被忽略的是:通道名、handler 的 channels 值、服务 ID 三者必须完全一致;另外,rotating_file 的 max_files 不设默认无限保留,线上机器磁盘可能悄无声息撑爆。











