Laravel队列任务中日志分级与HTTP请求一致,关键在于配置而非调用方式;需通过logging.php定义按级别分离的通道(如queue_error),并配合Supervisor的--log=stdout和stdout_logfile确保日志不丢失,且Log::error()不触发重试,须显式throw异常或调用fail()。

队列任务里怎么区分记录 info/warning/error 日志
直接用 Log::info()、Log::warning()、Log::error() 就行,Laravel 队列任务中日志分级和普通 HTTP 请求完全一致,底层走的都是同一个日志通道(比如 stack 或 single)。关键不是“能不能分”,而是“分了之后会不会被吞掉”或“有没有被重定向到别的地方”。
常见错误现象:Log::warning('xxx') 在队列里执行了,但日志文件里找不到;或者所有日志都挤在 laravel.log 里,没按级别分离。
- 默认配置下,
config/logging.php的stack通道会把所有级别日志合并写入同一文件,不会自动拆分 - 如果你启用了
stderr通道(比如 Supervisor 捕获 stdout/stderr),而队列进程没配--log=stderr,那Log::xxx()默认不输出到终端 -
Log::emergency()和Log::alert()这类高危级别会被某些日志驱动(如papertrail)强制转发,但info可能被静默丢弃——取决于level配置
想按 level 分文件?改 logging.php 配置就行
不用动队列代码,改日志通道配置即可。核心是为不同级别定义独立通道,再用 stack 统一接入,或直接在任务里指定通道名。
示例:在 config/logging.php 中加一个 queue_error 通道:
'queue_error' => [
'driver' => 'single',
'path' => storage_path('logs/queue-error.log'),
'level' => 'error',
'permission' => 0664,
],
然后在任务里写:Log::channel('queue_error')->error('任务失败:'.$e->getMessage());
- 每个通道的
level是过滤阈值,设成'error'就只记录 error 及以上(error、critical、alert、emergency) - 别用
daily驱动配低级别通道——每天切文件时,info.log可能空转,而error.log一天就几十行,不如全用single - 如果用
stack通道聚合多个子通道,注意子通道自己的level仍生效,不是“堆一起再过滤”
Supervisor 下日志消失?检查 --log 和 --delay 参数
Supervisor 启动 php artisan queue:work 时,如果不显式指定日志路径,Log::xxx() 写的还是 storage/logs/laravel.log,但 Supervisor 自己可能把 stdout/stderr 重定向到了别处,导致你以为“没日志”。
- 确保 Supervisor 配置里有
stdout_logfile=/var/log/supervisor/queue.log,否则终端输出直接丢弃 - 加上
--log=stdout参数,让队列命令把日志打到 stdout,这样 Supervisor 才能捕获:php artisan queue:work --log=stdout --delay=3 -
--delay影响的是任务失败后重试间隔,和日志无关,但很多人顺手抄错参数,结果发现日志延迟出现——其实是任务根本没跑,不是日志慢 - 别在
.env里设LOG_LEVEL=error,这会全局压制 info/warning,队列任务也受影响
异步任务里 throw Exception 和 Log::error() 的区别
这是最容易混淆的点:记录 error 日志 ≠ 触发失败重试。Laravel 队列是否重试,只看有没有抛出未捕获异常,和你记不记日志完全无关。
- 写了
Log::error('xxx')但没throw $e→ 任务标记为 success,日志写了,但错误被吞了 - 捕获异常后只
throw new Exception(...),没调Log::error()→ 任务重试,但没留下可查的上下文 - 最佳实践:先
Log::error(),再throw $e;或者用$this->fail($e)(针对ShouldQueue实现) - 如果用了
withoutFailures()或数据库 failed_jobs 表被禁用,那throw了也没法查,必须靠日志兜底
复杂点在于:日志级别只是标记严重性,真正决定流程的是异常流;而日志落盘位置、是否分割、能否被监控系统采集,全靠配置细节撑着——少配一个 level 或漏写 --log=stdout,整条链路就断一半。


















