php订单日志怎么在cli模式写_php命令行模式写订单日志教程【教程】

CLI订单日志须用fopen或file_put_contents配合date动态生成带日期的文件名(如order_2025-06-15.log),追加写入并加LOCK_EX防并发错乱,内容含order_id、status、microtime(true),路径用__DIR__拼绝对路径。

CLI 模式下写订单日志必须用 fopen 配合 date 手动拼路径

Web 环境下常见的 error_log() 或 Laravel 的 Log::info() 在 CLI 中可能不生效,尤其当 PHP 配置了 log_errors = Offerror_log 指向了 Web 专用日志文件时。CLI 进程没有 Apache/Nginx 的日志上下文,得自己管文件打开、格式、权限和换行。

推荐做法是:每次写日志前用 date('Y-m-d') 动态生成带日期的文件名(如 order_2025-06-15.log),再用 fopen($file, 'a') 追加写入。避免用 'w' 模式,否则每次覆盖。

  • fopen() 必须检查返回值,false 表示目录不存在或无写权限,需提前 mkdir -p 或抛异常
  • 日志行末尾务必加 \n,否则多条记录会挤在同一行
  • 不要在循环里反复 fopen/fclose,高频写入建议打开一次、批量写入、最后关闭

订单日志内容至少包含 order_idstatusmicrotime(true)

单纯记时间不够,订单状态变更(如 createdpaidshipped)必须可追溯。Web 请求里能从 $_POST 或路由参数取 order_id,CLI 命令则要靠 $argv 传入,比如:php order_process.php --order-id=ORD-20250615-001 --status=paid

microtime(true) 替代 date() 记毫秒级时间戳,方便排查并发或延迟问题;状态字段别只写中文,用英文标识符(pending/refunded)更利于后续 grep 或日志系统解析。

file_put_contents(
    '/var/log/myapp/order_' . date('Y-m-d') . '.log',
    sprintf(
        "[%s] order_id=%s status=%s cost=%.3f ms\n",
        date('Y-m-d H:i:s'),
        $argv[2] ?? 'unknown',
        $argv[4] ?? 'unknown',
        (microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']) * 1000
    ),
    FILE_APPEND | LOCK_EX
);

file_put_contentsLOCK_EX 是防止多进程日志错乱的关键

一个订单可能被多个 CLI 进程同时处理(如队列消费者),若不加锁,两行日志可能交叉写入,变成这样:[2025-06-15 10:00:00] order_id=ORD-1 status=paid[2025-06-15 10:00:01] order_id=ORD-2 status=shipped —— 中间缺换行,解析失败。

LOCK_EX 是排他锁,写入前阻塞其他进程,写完自动释放。注意:file_put_contents 的锁只对当前文件有效,不同日期的文件互不影响;但如果你用单个大日志文件(如 order_all.log),高并发下锁竞争会变严重,响应变慢。

  • 不要用 flock() 手动管理锁,file_put_contentsLOCK_EX 更简洁可靠
  • 如果日志量极大(每秒百条以上),考虑改用消息队列(如 Redis List + 后台写入线程),避免磁盘 I/O 成瓶颈
  • PHP-FPM 和 CLI 共用同一份日志路径时,注意 umask 和目录属组,CLI 进程可能以 www-data 外的用户运行,导致写权限不足

调试 CLI 日志时,先确认 getcwd()__DIR__ 是否符合预期

CLI 下当前工作目录(getcwd())取决于你从哪执行命令,不是脚本所在目录。比如你在 /home/user 下运行 php /var/www/app/cli/order.phpgetcwd()/home/user,此时相对路径 ./logs/order.log 会写到错误位置。

安全做法是全部用绝对路径,通过 __DIR__ 定位脚本目录再拼接,例如:__DIR__ . '/../storage/logs/order_' . date('Y-m-d') . '.log'。上线前用 php -r "echo getcwd();"php -r "echo __DIR__;" 对比验证。

另外,有些运维会禁用 allow_url_fopen,但这个设置不影响本地文件写入,别误判为配置问题。