HarmonyOS 应用实战 69:hilog 别记录用户正文,用事件码保留排障线索
开发时在 hilog 打出 question 和 answerText 很方便,但答案之书的用户问题、题库和答案都可能是私人内容。日志一旦被截图、导出或附在反馈里,正文就离开了设备。
本文解决四个问题:
- 用事件码替代用户正文
- 只记录安全 id、长度、数量和阶段
- 把日志格式集中管理
- 验证发布态不会输出题库全文
日志不是业务备份
日志的目标是定位阶段,不是复原用户内容。能用长度、计数、hash、事件码说明的问题,就不要打印原文。
泄露链:hilog.info('question=%s', question) -> 用户反馈截图 -> 私人问题进入工单 -> 排障通道变成泄露通道这篇和第 58 篇的边界不同:第 58 篇管用户可发送报告,第 69 篇管日志写入源头。日志本身不记录正文,导出时才不会被迫补救。
事件码先覆盖核心动作
事件码要稳定、可检索、可聚合。不要把自然语言错误散落在每个页面。
enumBookEventCode{StartupReady='STARTUP_READY',DrawCandidateEmpty='DRAW_CANDIDATE_EMPTY',FavoriteWriteFailed='FAVORITE_WRITE_FAILED',RouteParamInvalid='ROUTE_PARAM_INVALID'}事件码要覆盖核心动作,而不是让每个页面写一段自然语言。稳定事件码才能被搜索、聚合和发布前审计。
日志参数只允许白名单字段
安全字段包括阶段、事件码、deckId hash、候选数量、文本长度。正文不进入日志输出格式。
interfaceSafeLogPayload{code:BookEventCode;deckHash?:string;qLen?:number;candidateCount?:number;errorCode?:string;}白名单字段让日志保持可用:阶段、数量、长度、截断 id 可以定位故障,但不会还原用户问题。
BookLogger 统一输出格式
集中封装后,页面和服务不再直接拼 hilog 字符串。
classBookLogger{staticinfo(payload:SafeLogPayload):void{hilog.info(0x0001,'AnswerBook','code=%{public}s deck=%{public}s qLen=%{public}d count=%{public}d',payload.code,payload.deckHash??'-',payload.qLen??0,payload.candidateCount??0);}}BookLogger集中格式后,业务代码不再直接拼hilog.info。后续要调整公开字段,也只改一个 owner。
抽取链路记录长度,不记录问题
问题长度可以帮助判断空输入、超长输入和是否来自推荐,但不需要知道问题内容。
classDrawDiagnostics{logDrawStart(deckId:string,question:string,candidateCount:number):void{BookLogger.info({code:candidateCount>0?BookEventCode.StartupReady:BookEventCode.DrawCandidateEmpty,deckHash:Hash.sha256(deckId).slice(0,12),qLen:question.trim().length,candidateCount});}}抽取链路记录问题长度,不记录问题文本。长度足以区分空输入、超长输入和推荐入口,正文没有进入日志的必要。
发布前搜索敏感日志模式
不要只靠代码评审记忆。发布前用 rg 搜索常见危险字段和直接 hilog 调用。
rg-n"hilog\.(info|warn|error)|question|answerText|deckName|JSON.stringify"D:\ProgramData\huawei\lesson\The_Book_of_Answers发布前搜索敏感日志模式,是为了发现新增代码绕开 logger。JSON.stringify、questionText、answerText都应该被重点看。
hilog 排查表
日志越详细不一定越好,能定位阶段且不泄露正文才是正确目标。
| 现象 | 风险 | 修复 |
|---|---|---|
| 日志含 answerText | 泄露答案 | 改 answerId/hash |
| 页面直接 hilog | 输出格式不可控 | 统一 BookLogger |
| 只有错误文本无事件码 | 难检索 | 增加 BookEventCode |
如果日志里已经出现正文,先不要讨论导出报告怎么脱敏。源头日志改干净后,诊断导出才是真正安全的第二层。
先从源头禁止正文进入 hilog
第 58 篇解决“用户导出的报告怎么脱敏”,第 69 篇要往前一步:日志写入时就不接收正文。否则导出报告再安全,开发截图、临时附件和系统日志里仍可能出现敏感内容。
| 字段 | 是否进入日志 | 替代 |
|---|---|---|
questionText | 否 | qLen、事件码 |
answerText | 否 | answerId的安全片段 |
deckName | 否 | deckHash |
| 候选数量 | 是 | candidateCount |
这张白名单比“发布前记得删日志”可靠,因为它让业务代码没有传正文的入口。
发布前搜索要看直接调用和间接泄露
只搜hilog.info不够。JSON.stringify(deck)、错误对象拼接、临时console风格输出都可能把正文带进日志。发布前至少搜三类模式。
rg-n"hilog\.(debug|info|warn|error)"entry hsp har rg-n"questionText|answerText|deckName|JSON.stringify"entry hsp har rg-n"BookLogger\.info|BookLogger\.warn|BookLogger\.error"entry hsp har第一条找直接日志调用,第二条找敏感字段,第三条确认是否走统一 logger。命中不是一定错误,但每个命中都要判断是否会输出用户正文。
交付记录要区分日志和诊断报告
日志治理和诊断导出是两层证据。日志层证明源头不写正文;报告层证明用户复制出去的内容也只包含白名单字段。两层缺一层,都不要写“排障材料已安全”。
| 证据 | 证明 |
|---|---|
BookLogger白名单 | 日志调用格式受控 |
| 敏感字段搜索记录 | 新增代码没有绕过 logger |
| 脱敏报告样例 | 用户导出内容可发送 |
| 发布清单条目 | 日志、诊断和隐私口径已对齐 |
这篇文章的结论应限定为“日志写入策略和本地静态审计方法”,没有设备hilog输出记录时,不写真机日志已验证。
日志事件码要能回到业务动作
事件码不是越多越好。每个事件码都应该能回到一个业务动作和一个排查入口。比如DRAW_CANDIDATE_EMPTY回到抽取候选集,ROUTE_PARAM_INVALID回到路由守卫,FAVORITE_WRITE_FAILED回到收藏仓储写入。
| 事件码 | 业务动作 | 第一排查点 |
|---|---|---|
DRAW_CANDIDATE_EMPTY | 抽取答案 | 当前题库答案数量 |
ROUTE_PARAM_INVALID | 进入页面 | DrawingRouteGuard |
FAVORITE_WRITE_FAILED | 收藏写入 | FavoriteRepository.saveAll |
STARTUP_READY | 启动完成 | Preferences 与 AppStorage 水合 |
如果事件码不能指向排查点,它就只是另一种自然语言日志。第 69 篇要把“少打正文”和“仍能排障”同时讲清楚,否则读者会担心日志治理降低定位效率。
人工评审时抽一条日志反推定位能力
日志不记录正文以后,团队可能担心不好排障。最好的评审方式是随机抽一条安全日志,看它能否反推出下一步查哪里。
log: code=DRAW_CANDIDATE_EMPTY deck=ab12-cd34 qLen=6 count=0 下一步:查 deckHash 对应题库是否为空、候选过滤是否过严、当前 deckId 是否失效。 log: code=ROUTE_PARAM_INVALID deck=- qLen=0 count=0 下一步:查路由入口、参数构造和 DrawingRouteGuard。如果一条日志既没有正文,又能指向排查入口,说明事件码设计是有效的。若日志去掉正文后完全无法定位,就不是隐私治理的问题,而是事件码和上下文字段设计太弱。
最后一项看调试开关是否进入发布态
日志治理还要检查临时调试开关。开发阶段可能会为了排查问题临时打开 verbose 日志,发布前必须确认这些开关不会让正文重新进入输出。建议把开关名、默认值和 release 行为写进发布清单:debug 包可以放宽事件数量,release 包仍然只允许白名单字段。这样日志策略不会因为一次临时排障被悄悄改坏。
| 开关 | debug 行为 | release 行为 |
|---|---|---|
verboseLog | 可增加事件数量 | 仍禁正文 |
diagnosticsPreview | 可展示报告预览 | 只展示脱敏字段 |
小结
hilog 要留下排障线索,但不能留下用户正文。事件码、阶段、长度、数量和 hash 已经足够定位多数问题;直接打印 question、answerText 和 deckName 应从发布态代码里移除。