Symfony 7.0 默认不记录数据库查询日志,必须手动配置 MonologLogger 实例并绑定到 DBAL 的 logger 选项,否则即使启用 doctrine.dbal.logging 或 doctrine.orm.debug 也无实际 SQL 输出。

Monolog 服务没注册就用 LoggerInterface 会报错
注入 LoggerInterface 时,Symfony 默认只提供 logger 这个主通道的服务。如果你在 services.yaml 里没显式声明其他 logger(比如 monolog.logger.payment),又试图通过 monolog.logger.payment 的 service ID 注入,容器会直接抛出 ServiceNotFoundException。
- 要使用自定义 channel(如
payment),必须先在services.yaml中定义对应服务,并打上monolog.logger标签 - channel 名需和 service ID 一致:服务 ID 是
monolog.logger.payment,channel 就是payment - 别漏掉
arguments: ['payment']—— 这是 logger 实例的 channel 名,不是服务 ID - 若只用默认
logger,无需额外定义,直接LoggerInterface $logger即可
monolog.yaml 里 formatter 写错位置就没效果
很多人把 formatter: monolog.formatter.json 放在 handlers: 上层或整个 monolog: 块下,结果日志还是纯文本——因为 Monolog 只认 handler 级别的 formatter 配置。
- 必须写在具体 handler 下,例如
file:或rotated:的缩进内 - 确保该 handler 的
channels包含你记录日志时用的 channel(比如['main', 'payment']) - 开发环境若
kernel.debug: false,debug级别日志会被静默丢弃,即使 formatter 正确也看不到输出 - JSON 格式器默认不包含 trace、memory 等字段;要加,得自定义
JsonFormatter类并重写format()
数据库日志处理器容易引发循环写入和事务冲突
用 Doctrine 写日志到数据库时,EntityManager 的 flush() 本身会触发 SQL 查询,而这些查询又可能被 doctrine.dbal.logging: true 捕获,再走一遍你的 DB 日志处理器——形成死循环。
- 务必在数据库日志处理器中禁用
doctrinechannel,或在monolog.yaml的 handler 配置里排除它:channels: ["!doctrine"] -
flush()必须包在try/catch里,失败时降级到error_log()或静默丢弃,否则一次 DB 故障会让整个请求崩掉 - 不要在 dev 环境启用 DB 日志——每次请求多一次事务,容易因锁表或连接池耗尽导致响应变慢甚至超时
- 高并发下考虑改用 Messenger 异步写入,但要注意延迟和消息丢失风险
doctrine.dbal.logging 不等于应用日志,且默认不输出
设 doctrine.dbal.logging: true 只是打开 DBAL 内部日志收集开关,没有绑定 logger 实例的话,SQL 根本不会落地,Profiler 里看到的也只是内存快照,不可检索也不触发 Monolog 处理器。
- 必须手动把
logger选项指向一个Monolog\Logger实例,例如:logger: '@monolog.logger.doctrine' -
doctrine.orm.debug: true只影响 DQL 编译过程,和实际执行的 SQL 无关 - 生产环境严禁开启全量 SQL 日志——单条查询日志可能达几 KB,高频接口下几分钟就能撑爆磁盘或拖垮 DB
- 真要排查问题,优先配置慢查询日志(
slowloghandler)或错误 SQL 日志(level: error),而不是 dump 所有语句
doctrine.dbal.logging 和应用日志是两套体系,也没想到 DB 日志处理器自己会触发新 SQL —— 这些链路一旦没断开,轻则日志重复爆炸,重则请求雪崩。


















