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

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

1. 目标

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

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

2. 已确认方案

复用现有 ReaderLog 和 ReaderLogStore:

不采用以下方案:

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 用户开始全量同步 syncId、batchSize
CUSTOMER_SYNC_COUNT_SUCCESS 用户总数请求成功 syncId、expectedCount、requestMs
CUSTOMER_SYNC_SUCCESS 全部批次保存并完成旧数据清理 syncId、expectedCount、savedCount、batches、databaseCount、elapsedMs
CUSTOMER_SYNC_FAILURE 任一阶段失败并完成失败标记 syncId、stage、batch、savedCount、successfulBatches、stageMs、elapsedMs、异常类型和消息

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

4.2 批次级事件

事件 时机 记录字段
CUSTOMER_SYNC_BATCH_START 本批开始 syncId、batch、startingCustomerId、requestedCount
CUSTOMER_SYNC_REQUEST_SUCCESS SOAP 响应成功返回 上述定位字段、requestMs、responseBytes
CUSTOMER_SYNC_PARSE_SUCCESS XML 解析成功 syncId、batch、records、parseMs
CUSTOMER_SYNC_SAVE_SUCCESS SQLite 事务提交成功 syncId、batch、batchSaved、totalSaved、saveMs、batchMs

失败不为每个阶段再建立独立事件名,统一写 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. 非目标