调度任务输出默认不记录,需显式配置output()或emailoutputonfailure();output()仅捕获命令stdout/stderr,不捕获php致命错误;多服务器需用ononeserver()或统一日志系统避免日志分散。

调度任务的输出默认不记录,必须显式配置才会落盘或发邮件;不配就等于没执行过。
schedule()->output() 写日志文件要确认路径可写
用 output() 把命令输出存到文件是最直接的方式,但容易因权限或路径问题静默失败:
-
storage_path('logs/email.log')是常见选择,但需确保storage/logs/目录存在且 Web/CLI 进程有写权限(如 PHP-FPM 用户、crontab 执行用户) - 路径不能是相对路径,
./logs/schedule.log会写到 cron 当前工作目录(通常是/root或/var/www),不是你预期的位置 - 建议用绝对路径 +
storage_path()辅助函数,避免硬编码 - 首次运行前手动 touch 并 chmod:
touch storage/logs/schedule.log && chmod 644 storage/logs/schedule.log
sendOutputTo() 和 emailOutputOnFailure() 的触发条件不同
sendOutputTo() 记录所有输出(含 stdout/stderr),而 emailOutputOnFailure() 只在命令非零退出时发邮件:
-
$schedule->command('emails:send')->daily()->sendOutputTo('/storage/logs/email.log'):哪怕命令成功,日志里也会有 “Command completed successfully” -
$schedule->command('backup:run')->hourly()->emailOutputOnFailure('admin@example.com'):只有backup:run抛异常或 exit(1) 才触发邮件 - 两者可共存,但注意邮箱发送依赖 Laravel 的 mail 配置(
MAIL_MAILER等),且部分 SMTP 服务对频繁小邮件有限流
output() 重定向不捕获 PHP 错误和未捕获异常
output() 只接管 Artisan 命令本身的 stdout/stderr,PHP 解析错误、Fatal Error、未 catch 的 Exception 不会进这个文件:
- 比如命令里写了
undefined_function(),你会在php-fpm错误日志或syslog里看到,但output()文件里空空如也 - 真正兜底的是 Laravel 日志通道(
Log::error()),它能捕获App\Exceptions\Handler处理的所有异常 - 若想统一收集,应在命令的
handle()方法开头加Log::channel('schedule')->info('started'),结尾加Log::channel('schedule')->info('finished')
多服务器部署时 output() 文件可能被覆盖或丢失
当多个服务器都运行同一个调度任务(比如负载均衡后多台 Web 节点都配了 cron),output() 会各自写本地文件,导致日志分散、无法聚合:
- 除非明确用了
onOneServer(),否则不要依赖单个日志文件做监控或告警 - 更可靠的做法是把输出通过
Log::channel('stack')写入统一日志系统(如 ELK),或用sendOutputTo()+ NFS 共享目录(但要注意并发写入冲突) - 如果只是调试,临时加
->append()避免每次覆盖,但生产环境慎用——日志文件会无限增长
最常被忽略的一点:cron 条目里的 >>/dev/null 2>&1 会吞掉 schedule:run 自身的报错,比如找不到命令、内存溢出、PHP 解析失败——这些根本不会进你配的 output() 文件,得去系统 cron 日志(/var/log/syslog 或 journalctl -u cron)里翻。











