OnecardDemo 用户全量同步分阶段耗时日志设计

日期:2026-08-24
状态:已实施,待真机与现场全量同步验证

1. 目标

为“获取全部用户信息(分段)”增加可追溯的分阶段耗时日志,用来判断现场全量同步的主要耗时发生在服务器请求、XML 解析还是 SQLite 保存。

本功能只写现有应用本地日志,不新增数据库表,不把耗时明细写入 onecard.db,不增加新的页面控件,也不改变当前用户数据分页、解析和保存语义。

2. 已确认方案

复用现有 ReaderLogReaderLogStore

不采用以下方案:

3. 计时口径

耗时使用 ReaderLog.mark()ReaderLog.elapsedMs(),底层为 System.nanoTime() 单调时钟。系统时间被人工修改或网络校时不会影响已开始阶段的耗时。

每批计时边界如下:

指标 开始点 结束点 是否包含后续阶段
请求耗时 requestMs 调用 getCustomers 之前 完整 SOAP 响应返回或抛出异常
解析耗时 parseMs 调用 CustomerBatchParser.parse 之前 返回全部 CustomerRecord 或抛出异常
保存耗时 saveMs 调用 repository.saveBatch 之前 SQLite 批事务提交完成或抛出异常
单批总耗时 batchMs 本批网络请求之前 保存事务提交并完成进度计算
同步总耗时 elapsedMs 获取服务器用户总数之前 全量完成或失败处理结束

毫秒结果允许为 0,表示该阶段在当前时钟精度下不足1毫秒,不表示阶段没有执行。

4. 日志事件

4.1 同步级事件

事件 时机 记录字段
CUSTOMER_SYNC_START 用户开始全量同步 syncIdbatchSize
CUSTOMER_SYNC_COUNT_SUCCESS 用户总数请求成功 syncIdexpectedCountrequestMs
CUSTOMER_SYNC_SUCCESS 全部批次保存并完成旧数据清理 syncIdexpectedCountsavedCountbatchesdatabaseCountelapsedMs
CUSTOMER_SYNC_FAILURE 任一阶段失败并完成失败标记 syncIdstagebatchsavedCountsuccessfulBatchesstageMselapsedMs、异常类型和消息

GetCustomerCount 也是一次服务器请求,因此单独记录 requestMs

4.2 批次级事件

事件 时机 记录字段
CUSTOMER_SYNC_BATCH_START 本批开始 syncIdbatchstartingCustomerIdrequestedCount
CUSTOMER_SYNC_REQUEST_SUCCESS SOAP 响应成功返回 上述定位字段、requestMsresponseBytes
CUSTOMER_SYNC_PARSE_SUCCESS XML 解析成功 syncIdbatchrecordsparseMs
CUSTOMER_SYNC_SAVE_SUCCESS SQLite 事务提交成功 syncIdbatchbatchSavedtotalSavedsaveMsbatchMs

失败不为每个阶段再建立独立事件名,统一写 CUSTOMER_SYNC_FAILURE,通过 stage=count/request/parse/save/complete 区分失败位置,stageMs 记录失败阶段从开始到抛出异常的耗时,避免失败请求丢失耗时证据。

5. 响应大小和安全边界

responseBytes 使用原始 SOAP XML 的 UTF-8 字节数计算,只记录长度,不保存响应内容。

允许记录的定位信息:

禁止写入日志的内容:

异常消息沿用现有错误传播,但日志实现不得主动拼接或附加原始 SOAP 内容。日志写入失败继续按 ReaderLog 的既有规则降级到 Logcat,不影响同步业务。

6. 代码边界

为保持 JVM 单元测试可运行,CustomerSyncService 不直接硬编码静态日志调用;增加小型 SyncLogger 接口,生产实现委托给 ReaderLog,测试使用内存 fake 验证事件和耗时字段。该接口只承担同步日志,不扩展为通用日志框架。

7. 错误处理

8. 测试与验收

8.1 自动测试

8.2 现场验收

执行一次全量同步后,在“查看读卡日志”中搜索 CUSTOMER_SYNC_,每个成功批次应依次出现开始、请求成功、解析成功和保存成功事件;最终出现同步成功或失败事件。所有耗时必须为非负毫秒值,日志中不得出现用户原始字段值。

9. 非目标