php订单日志怎么记录发货_php记录订单发货操作日志指南【指南】

不能只用 error_log() 记录发货日志,因其缺乏订单号上下文、时间格式混乱、多进程写入错乱,且不支持事务绑定,易导致对账偏差;可靠方案是用数据库表 order_shipping_log 存储结构化日志,确保与订单强关联、事务一致、可检索。

为什么不能只用 error_log() 记录发货日志

直接调用 error_log() 写发货日志,看起来简单,但很快会出问题:日志没订单号上下文、时间格式混乱、多进程写入时内容错乱、查不到谁在什么时间发了哪笔货。PHP 默认日志不带事务绑定,发货成功但日志写失败,或日志写了但发货回滚,都会导致对账偏差。

真正可用的发货日志必须满足三点:与订单强关联、与数据库操作同事务(或至少可回溯)、字段结构化便于检索。

  • 必须记录 order_idshipping_nologistics_companyoperator_idcreated_at
  • 日志写入动作应放在发货逻辑确认提交之后(如 $pdo->commit() 后),或使用数据库表+触发器兜底
  • 避免用 file_put_contents() 追加到公共文件——并发高时易丢行、无原子性

用数据库表记录发货日志最稳妥

建一张 order_shipping_log 表,比文件日志更可靠,能和订单表做 JOIN 查询,也方便加索引查异常单。字段不必复杂,但 order_idstatus 是关键。

CREATE TABLE `order_shipping_log` (
  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  `order_id` BIGINT UNSIGNED NOT NULL,
  `shipping_no` VARCHAR(64) DEFAULT '',
  `logistics_company` VARCHAR(32) DEFAULT '',
  `operator_id` INT UNSIGNED NOT NULL,
  `remark` TEXT,
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_order_id` (`order_id`),
  KEY `idx_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  • 插入日志前,确保 order_id 已存在且状态合法(比如是 'paid''confirmed'
  • 不要在事务里 INSERT 日志再 COMMIT —— 若后续发货失败回滚,日志却已落库,造成脏数据;应在发货成功 COMMIT 后立即 INSERT
  • 如果用 Laravel,可用 DB::transaction() 包裹发货逻辑,再单独 DB::table('order_shipping_log')->insert(...)

用 Monolog 写文件日志要绕开三个坑

若业务强制要求写文件(如审计合规),Monolog 是比裸写文件更可控的选择,但默认配置容易翻车。

  • 别用 StreamHandler 直接写 php://stdout 或未加锁的普通文件——并发下日志行会粘连
  • 必须用 RotatingFileHandler 并设置 maxFiles=30,否则日志无限增长,ls -l 都卡住
  • Formatter 必须自定义,把 order_idshipping_no 注入上下文,否则 grep 时找不到目标单:
    $logger->info('发货完成', [
        'order_id' => $order->id,
        'shipping_no' => $trackingNo,
        'logistics' => $company,
        'operator' => $adminId
    ]);

发货日志和订单状态更新必须有因果顺序

这是最容易被忽略的逻辑断点。很多系统先更新订单表 status = 'shipped',再写日志,看似合理,但如果写日志时抛出异常(如磁盘满、权限不足),订单已变更为“已发货”,但无据可查——财务或客服查不到谁、何时、用哪家快递发的货。

正确做法只有两种:

  • 数据库方案:发货状态变更和日志插入,在同一事务中完成(推荐用存储过程或应用层显式事务控制)
  • 补偿方案:先写日志(状态为 'pending'),再更新订单;若订单更新失败,则异步任务扫描 status = 'pending' 的日志,重试或告警
  • 绝对不要依赖“先改状态,再写日志”这种弱一致性链路

真实线上环境里,磁盘满、MySQL 主从延迟、ORM 自动 commit 模式切换,都可能让“写完日志再改状态”变成伪命题。因果顺序不是编码风格问题,是资金和履约安全的底线。