绑盘机消费业务全链路日志规划

2026-08-28 补充确认:日志最终统一保存到设备外部存储根目录 /Log/;新写入 JSONL 的核心字段名使用中文,查看器继续兼容旧英文 key。本文后续关于“应用内部独立目录”和英文 JSON 示例的早期内容,以本补充确认及实施记录 V1.1 为准。调整原因是便于现场统一查找日志,并让导出的原始文件可直接阅读。

版本:V1.0
日期:2026-08-28
适用范围:ConsumptionActivity 放盘、订单查询、一卡通交易、本地落库、接口 C 前台反馈及后台补传

1. 规划结论

新增独立的 ConsumptionFlowLog 业务流水日志类型,以“一张餐盘对应的一笔订单会话”为主线,完整记录:

放盘 → 查询订单 → 金额分流 → 等待卡片 → 消费前读卡 → 扣款 → 消费后读卡 → 本地保存 → 接口 C → 后台补传 → 会话结束

业务流水只记录可读、可检索的业务摘要,不复制一卡通协议原文和 HTTP 完整报文。现有日志继续承担各自职责:

日志层 主要用途 是否新增 关联方式
ConsumptionFlowLog 按订单查看完整业务时间线 flowIdorderNo
ReaderLog USB、寻卡、APDU、钱包扣款等硬件诊断 readerSession、时间戳
网络原始日志 HTTP URL、请求、响应和传输异常 否,但需脱敏检查 apiName、时间戳、reportAttemptId
consumption_records.db 交易事实、接口 C 原请求和可靠补传 orderNo

记录原因:当前关键信息分散在 Activity、读卡协议日志、HTTP 日志和本地数据库中,不能直接回答“一笔订单从放盘到反馈经历了什么”。独立业务流水既能解决现场可读性,也不会把调试噪声和敏感原文混入主链路。

2. 设计原则

  1. 一笔业务一个 flowId:餐盘首次识别成功时创建,直到统一复位才结束。
  2. 订单号出现后全程携带:订单查询成功前 orderNo 允许为空,成功后每个事件必须带订单号。
  3. 阶段开始和结果成对:网络请求、前读卡、扣款、后读卡、落库、接口 C 都必须有开始及结果事件。
  4. 日志失败不得影响交易:日志属于可观测性能力,写入失败只降级到 Logcat,绝不阻塞读卡、扣款、落库或反馈。
  5. 交易事实仍以数据库为准:业务日志用于解释过程,不替代 consumption_records.db
  6. 默认脱敏:不写 Access-Token、人员姓名、客户号、完整卡号、完整 UID、原始 APDU、完整请求体或响应体。
  7. 低噪声:无卡轮询、重复扫码帧等高频事件不逐条记录,只记录状态变化和有效业务节点。
  8. 可直接阅读,也可程序解析:文件采用 UTF-8 JSON Lines,一行一个事件;管理端按字段渲染成人类可读时间线。

3. 会话与关联键

3.1 flowId

3.2 其他关联键

字段 来源 用途
orderNo 接口 B 关联订单、交易记录和接口 C
trayCode 餐盘扫码器 关联放盘与订单查询;日志中按配置决定原值或掩码
readerSession ReaderLog.getSession() 跳转到一卡通协议明细
reportAttemptId 每次接口 C 调用生成 区分前台首次上传和后台第 N 次补传
eventSequence 每个 flowId 单调递增 保证同毫秒及异步回调仍可正确排序

后台补传可能发生在原页面会话结束或应用重启后,因此待上传记录需要持久化 flowId;数据库版本升级时为旧记录允许生成 legacy-{orderNo} 兼容标识。

4. 单条日志字段契约

每行至少包含以下字段:

字段 必填 说明
schemaVersion 首版固定为 1
timestamp ISO-8601 本地时间,精确到毫秒
elapsedRealtimeMs 设备单调时钟,用于计算耗时,不受系统校时影响
eventSequence 当前业务会话事件序号
level INFOWARNERROR
event 稳定事件码,禁止直接使用页面中文文案
flowId 业务会话标识;全局网络事件可为 GLOBAL
orderNo 条件必填 订单查询成功后的事件必须有值
trayCode 条件必填 放盘、移盘、订单查询事件使用
stage TRAYORDERCARD_BEFOREDEBITCARD_AFTERLOCAL_SAVEREPORTRESET
result STARTEDSUCCEEDEDFAILEDPENDINGSKIPPEDUNKNOWN
durationMs 阶段结束事件耗时
amount 订单应付金额,单位分
completedAmount 实际确认扣款金额,单位分
errorCode 稳定错误码或服务端业务码
errorMessage 清洗换行并限制长度的错误摘要
apiName ACQUIRE_BY_PLATEONE_CARD_REPORT
traceId 服务端返回的链路标识
reportSource FOREGROUNDSCHEDULED_RETRYAPP_STARTNETWORK_RECOVERY
reportAttemptId 单次反馈尝试标识
readerSession 关联硬件日志会话
details 仅允许白名单字段的 JSON 对象

示例:

{"schemaVersion":1,"timestamp":"2026-08-28T10:20:31.256+08:00","elapsedRealtimeMs":8732140,"eventSequence":12,"level":"INFO","event":"DEBIT_RESULT","flowId":"e806...","orderNo":"O202608280001","stage":"DEBIT","result":"SUCCEEDED","durationMs":736,"amount":1250,"completedAmount":1250,"readerSession":4,"details":{"walletCount":2}}

5. 完整事件清单

5.1 应用、网络和日志自身

事件码 触发时机 关键字段
FLOW_LOG_INITIALIZED 日志系统初始化 目录、保留天数、单文件限制
FLOW_LOG_WRITE_FAILED 文件写入异常并降级 Logcat 错误摘要;需要限频
NETWORK_STATUS_CHANGED 网络可用性状态变化 connected、validated、available

5.2 放盘与订单

事件码 触发时机 关键字段
FLOW_CREATED 第一张有效餐盘建立会话 flowId、trayCode
TRAY_DETECTED 有效餐盘识别成功 trayCode
TRAY_CODE_IGNORED 会话锁定期间收到重复码或其他码 原因;限频
TRAY_REMOVED 物理移盘 当前状态、是否提前移走
ORDER_REQUEST_STARTED 调用接口 B 前 apiName、设备编号是否已配置
ORDER_REQUEST_RESULT 接口 B 返回 result、durationMs、业务码、traceId
ORDER_VALIDATED 订单字段校验结束 orderNo、amount、result
PAYMENT_DECISION 按金额分流 ZERO_AMOUNTCARD_PAYMENT

5.3 卡片与一卡通交易

事件码 触发时机 关键字段
CARD_ZONE_NOT_CLEAR 第三步发现遗留卡 result=PENDING
CARD_ZONE_READY 已确认无卡,可等待新卡 readerSession
PAYMENT_ARM_RESULT 订单武装读卡交易 result、orderNo、amount
CARD_DETECTED 本次支付检测到新卡 readerSession;不记录完整 UID
CARD_BEFORE_STARTED 消费前读卡开始 readerSession
CARD_BEFORE_RESULT 消费前读卡结束 result、durationMs、错误码
DEBIT_STARTED 扣款命令开始 amount
DEBIT_RESULT 扣款结束 completedAmount、walletCount、result、错误码
CARD_AFTER_STARTED 消费后复读开始 readerSession
CARD_AFTER_RESULT 消费后复读结束 result、durationMs、错误码
CARD_CONSISTENCY_RESULT 前后卡及金额校验 result、校验失败类型
TRANSACTION_CLASSIFIED 最终交易分类 DEBIT_SUCCEEDEDPRE_DEBIT_FAILEDDEBIT_UNKNOWN

ConsumptionCardTransactionExecutor 的三个真实阶段作为开始事件;ConsumptionTransactionOutcome 统一产生三个结果事件,避免在底层和 Activity 重复记同一业务事件。

5.4 本地记录与接口 C

事件码 触发时机 关键字段
LOCAL_RECORD_SAVE_STARTED 订单或交易准备落库 recordType
LOCAL_RECORD_SAVE_RESULT 落库结束 result、durationMs、错误码
REPORT_ENQUEUED 接口 C 原请求已持久化 reportStatus、nextRetryAt
REPORT_REQUEST_STARTED 每次接口 C 调用前 reportSource、reportAttemptId、attemptNumber
REPORT_REQUEST_RESULT 接口 C 返回 result、durationMs、业务码、traceId、错误摘要
REPORT_MARK_RESULT 本地标记上传成功或失败 UPLOADEDPENDING
RETRY_ROUND_STARTED 后台补传轮次开始 trigger、batchSize、maxPerRound
RETRY_ITEM_RESULT 单条补传结束 orderNo、attemptId、result
RETRY_ROUND_FINISHED 补传轮次结束 attempted、uploaded、failed、skipped、durationMs

5.5 终态与复位

事件码 触发时机 关键字段
FLOW_TERMINAL 进入成功、待补传或交易异常终态 terminalState、trayPresent、cardPresent
FLOW_RESET_WAITING 仍等待餐盘或卡片移走 waitingFor
FLOW_FINISHED 本轮安全结束 finalState、totalDurationMs、reportStatus
FLOW_RESET 返回等待放盘 result=SUCCEEDED
ACTIVITY_BACKGROUND_DURING_TRANSACTION 硬件交易在途时进入后台 当前交易阶段

6. 文件保存、轮转和查看

6.1 保存方式

不直接复用 LocalFileRecorder,原因是其日志混合保存在外部 /Log/、缺少结构化字段和业务会话序号,并通过剩余空间循环删除其他类别文件,不适合作为交易主链路日志。

6.2 查看能力

在管理员日志入口新增“消费流水”类型:

7. 脱敏和安全规则

7.1 禁止写入业务流水

7.2 允许的业务摘要

同时需要修复现有 NewLogInterceptor 的空请求体 reqBody.toString() 风险,并对 headers/body 制定脱敏策略;该修复属于网络日志安全加固,不改变接口报文。

8. 实施任务与验收

Task 1:建立日志契约和文件存储

范围: 新增事件模型、上下文、JSON 编码、顺序写入、轮转和保留策略。

验收标准:

验证: 纯 Java 单测覆盖序列、转义、轮转、保留和写入失败。

依赖: 无。
预计范围: M,4至5个新增文件。

Task 2:接入放盘、订单和会话终态

范围: 在状态机、订单协调器和 Activity 接入 flowId,记录放盘、移盘、订单请求、金额分流及复位。

验收标准:

验证: 扩展状态机与订单协调器单测,核对固定事件序列。

依赖: Task 1。
预计范围: M,3至4个文件。

Task 3:接入一卡通三阶段交易

范围: 记录遗留卡、等待新卡、前读卡、扣款、后读卡、卡一致性和交易分类;消除 Activity/Manager 重复的交易开始日志。

验收标准:

验证: 扩展 ConsumptionCardTransactionExecutorTest 和状态事件序列测试。

依赖: Task 1、Task 2。
预计范围: M,3至5个文件。

Checkpoint A:核心交易流水

Task 4:接入本地落库、接口 C 和后台补传

范围: 记录落库结果、前台接口 C、补传触发来源、每条补传及轮次汇总;持久化 flowId

验收标准:

验证: 仓库升级测试、补传Runner测试及重启恢复测试。

依赖: Task 1、Task 2。
预计范围: M,4至5个文件。

Task 5:接入网络状态并加固原始网络日志

范围: 记录网络状态变化;修复空请求体风险;对认证头和敏感字段脱敏。

验收标准:

验证: 网络状态去重测试、拦截器空Body和脱敏测试。

依赖: Task 1。
预计范围: M,3至4个文件。

Task 6:增加消费流水查看与导出

范围: 管理员日志入口增加消费流水类型,支持筛选、时间线和导出。

验收标准:

验证: 查询/过滤单测、页面手工检查、导出文件解析检查。

依赖: Task 1至5。
预计范围: M,4至5个文件。

Checkpoint B:完整可观测性

9. 实施顺序和预计工作量

建议严格按 Task 1 → 2 → 3 → Checkpoint A → 4 → 5 → 6 → Checkpoint B 推进。Task 4 与 Task 5 在日志契约稳定后可以独立开发,但合并验证必须串行。

本地代码、单测、文档和 Debug 构建预计需要1至2个开发日;真机至少需要一次成功交易、三次阶段移卡、一次断网补传和一次应用重启恢复测试。实际资金卡测试仍由用户提供设备和环境协助。

10. 不纳入本次范围

11. 最终验收口径

随机拿到一个 orderNo 后,无需同时翻查多个文件,就能在“消费流水”中回答:

  1. 什么时候放盘、餐盘是否提前移走;
  2. 订单请求是否成功、耗时多久、金额是多少;
  3. 是否零元;零元何时完成只读卡、正金额何时进入一卡通支付;
  4. 前读卡、扣款、后读卡分别是否成功、失败在哪一步;
  5. 本地记录是否保存成功;
  6. 接口 C 首次是否成功,失败原因是什么;
  7. 后台何时补传、尝试几次、最终是否上传成功;
  8. 会话何时安全结束并允许下一张餐盘。

能够完整回答以上8个问题,且业务流水中没有敏感原文,才算全链路日志实施完成。