Symfony默认不写日志文件,需手动配置Monolog的handlers和channels;常见问题包括handler未接入主日志流、kernel.debug=false导致debug日志被全局过滤、路径未用%kernel.logs_dir%变量、dev环境未显式启用rotating_file handler。

Symfony 默认不写日志文件,var/log/dev.log 为空是正常现象;想让日志真正落盘、按天轮转、分通道管理,必须手动配置 Monolog 的 handlers 和 channels。
为什么加了 rotating_file 还没日志?
常见原因是 handler 没接上主日志流,或被全局 debug 过滤截断:
-
channels配置错位:handler 的channels是“这个 handler 处理哪些 channel”,不是“把哪些 channel 塞进来”;漏掉main就等于没接上主日志流 -
kernel.debug: false时,debug 级别日志会被全局过滤——即使 handler 设了level: debug也无效,必须同步调高monolog.handlers.file.level和monolog.channels.main.level - 路径用了相对路径如
logs/app.log,实际会拼到项目根目录下,而非var/logs/;务必用'%kernel.logs_dir%/app.log' - 开发环境默认只启用
consolehandler,rotating_file必须显式加在config/packages/dev/monolog.yaml的handlers:下
怎么让日志按天切分并自动清理?
用 rotating_file 类型处理器,它比 stream 更实用:自动按日期命名(如 app-2026-05-14.log),超 max_files 就删最旧的。
在 config/packages/dev/monolog.yaml 或 config/packages/prod/monolog.yaml 中添加:
handlers:
file:
type: rotating_file
path: '%kernel.logs_dir%/app.log'
level: debug
max_files: 10
channels: ['!event', '!doctrine']
-
channels: ['!event', '!doctrine']是为了防日志爆炸,尤其开发时高频 dispatch event -
type: rotating_file的文件名格式固定为{filename}-{date}.{extension},想改命名得自定义 handler 类 - Symfony 6+ 强制每个 handler 显式声明
channels,不再支持旧写法handlers: [console, file]
如何为支付、用户等业务建独立日志文件?
拆通道是最直接的隔离方式,但要注意声明 + 绑定 + 注入三步缺一不可:
- 先在
config/packages/monolog.yaml里声明通道:channels: ['payment', 'user', 'api'] - 再为每个通道配专用 handler,例如:
payment: type: stream path: '%kernel.logs_dir%/payment.log' level: info channels: ['payment']
- 在服务中获取:
$this->get('monolog.logger.payment'),或更推荐用标签自动注入:App\Service\PaymentService: tags: [{ name: monolog.logger, channel: payment }]然后构造函数写public function __construct(LoggerInterface $logger) - HTTP 请求日志默认走
requestchannel,若想捕获,需显式加入 handler 的channels列表
生产环境日志写不进文件?重点查这三点
生产环境问题往往更隐蔽,权限、抑制、通道绑定都可能卡住:
-
suppress_php_warnings: true(默认开启)会导致 PHP 警告被 Symfony 层提前吞掉,Monolog 根本收不到——这不是配置问题,是框架行为 - 检查
var/log/目录权限,确保 web server 用户(如 www-data)有写权限,且 SELinux/AppArmor 没拦截 - 确认
monolog.handlers.file.channels包含了你期望的 channel,比如main或自定义名;漏掉就等于没路由过去 - 如果用了
fingers_crossed这类缓冲型 handler,它只在触发特定 level 后才 flush 日志,调试时容易误判为“没写入”
真正麻烦的不是加几行配置,而是理解 channels 是路由开关、level 是双层过滤、handlers 是输出终端——三者错一个,日志就静音。


















