真正起作用的是config/logging.php中每个channel的level字段,LOG_LEVEL仅在未显式配置时兜底生效;level必须为字符串如'error',设后环境变量即失效,且daily等driver严格按level过滤写入。

config/logging.php 里 level 配置才是真开关
日志级别控制不靠 LOG_LEVEL 环境变量“一键生效”,它只在 channel 没显式设 level 时兜底。真正起作用的是 config/logging.php 中每个 channel 的 level 字段。
比如你配了 'daily' 通道但没写 level,它会继承默认值(通常是 debug);但如果你在 stack 里嵌套了 daily 和 slack,那 slack 的 level 必须单独设,否则可能收不到 error 日志。
-
level值必须是字符串:'error'、'warning'、'info'等,不能写LogLevel::ERROR或数字 - 一旦写了
'level' => 'error',LOG_LEVEL就完全失效 - 别在
.env里写APP_LOG_LEVEL—— Laravel 9+ 已弃用,只认LOG_LEVEL
daily 驱动的 level 过滤发生在写入前
daily 驱动严格按 level 过滤:设成 'warning',Log::info() 就不会落盘,哪怕你调用的是 Log::channel('daily')->info()。
这个过滤是 Monolog 在写入文件前做的,不是靠后续 grep 或 logrotate 实现。所以别指望“先全记再筛选”——没被 level 放行的日志,连打开文件句柄这一步都不会走。
-
'days' => 14只影响轮转天数,和 level 无关 -
daily和single都严格遵循 level,但stderr或syslog可能忽略它,直接转发给系统服务 - 测试是否生效?别只看
storage/logs/laravel.log,要确认你调用的是哪个 channel:Log::channel('daily')->error('test')
stack 通道里多个子 channel 的 level 各自独立
stack 本身不处理日志,只是分发器。它把同一条日志广播给所有子 channel,但每个子 channel 按自己的 level 决定要不要接收。
常见坑是:你设了 stack 包含 daily(level = 'info')和 slack(level = 'error'),然后调用 Log::channel('stack')->warning('xxx') —— daily 会写,slack 会跳过。这不是 bug,是设计如此。
- 如果某个子 channel(如 Slack Webhook)写入失败,默认静默跳过;要抛错得设
'ignore_exceptions' => false - 子 channel 的
driver行为会影响最终结果:比如slack默认只传error及以上,即使你设了level='warning',也得配合 tap 处理器才能改掉这个限制 - 用 Monolog 自定义 driver 时,level 可能被 handler 二次过滤,得看具体实现
循环日志场景下 level 错配的真实代价
在 daily 这类循环日志驱动里,level 错配不是“少记几条”,而是直接导致关键告警静默丢失,或磁盘被 debug 日志撑爆。
比如生产环境误配 'level' => 'debug',Eloquent 查询的 bindings(含密码明文)全进 laravel-2026-06-14.log;又或者审计通道设成 'level' => 'error',那 Log::channel('audit')->info('用户登出') 根本不落地,审计链就断了。
- 事务内异常堆栈只在
error级别及以上才完整记录,info或warning会丢上下文 -
critical及以上才触发 syslog 的LOG_CRIT标志,集中式日志系统若只抓crit,低级别日志就进不了 pipeline - 最麻烦的是:日志级别是「写入门槛」,不是「触发条件」——写一条
info日志,不会自动唤醒error通道的任何行为


















