Appearance
稳定性诊断工具三件套
车道级业务的排障曾经全靠人眼翻日志:一条 logcat 上万行、record 文件是私有二进制、tombstone 里全是裸地址。我做了三个工具分别吃掉这三类脏活——GBL 一键诊断把 9 级数据管道的排查从 30 分钟以上压到一键出报告,HCrash 把 IL2CPP 崩溃符号化做成向导,万能解密工具把日志解密分析迭代到 V13 并封装成 AI Skill。
排查耗时≥30min → 一键
诊断维度4 个正交
解密工具迭代V4 → V13
背景
车道级(GBL)数据从云端到渲染要经过 9 级管道:高德 SDK → OnSRCallback → FetchOnce → DeltaRecorder → SignalDispatcher → FileRecorder(.record) → Replayer → Accumulator → Unity 渲染。每一级都可能出问题:频率异常、数据结构损坏、性能卡点、回放错位。与此同时,线上 IL2CPP 崩溃要靠人工对版本、下符号表、跑 addr2line;现场日志包是加密的 .xlog/.alog/.xp,还嵌套压缩包。三件事的共同点是:重复、机械、但每次都要花工程师半小时以上。
问题
| 场景 | 痛点 | 后果 |
|---|---|---|
| 车道级数据异常 | logcat 上万行 + 私有二进制 record,人工排查一次至少 30 分钟 | 容易遗漏,结论不可复用 |
| IL2CPP 崩溃 | 版本链长:ROM → APK → lib_napa5 → 带符号 so,全靠人工对齐 | 版本对错一步,符号化全是「??」 |
| 现场日志分析 | 加密格式嵌套压缩包,解密后还要从海量日志里捞关键场景 | 大量时间花在预处理而不是分析 |
车道级那个问题,用第一性原理拆开看,本质不是「日志太多」,而是「非结构化的海量信号需要按因果链归类、提炼成可执行的诊断结论」。所以工具只做三件事:Parse(非结构化 → 结构化对象)、Analyze(按因果类别检测异常)、Report(结论变成人能秒懂的可视化)。不在这三步里的功能都是噪声。
方案
GBL 车道级一键诊断:三段式 + 四个正交维度
所有故障归入四个互不重叠的类别——频率、完整性、链路卡点、回放。这是「不可再分」原则:如果哪个异常不属于任何一类,说明分类体系该扩展了,而不是硬塞。
mermaid
flowchart TD
IN["logcat 上万行<br>.record 私有二进制"] --> P["Parse<br>LogLine / FrameInfo"]
P --> D["ParsedData<br>结构化对象"]
D --> A1["频率分析<br>回调间隔 / 时钟跳变"]
D --> A2["完整性分析<br>null texture / 位置跳变"]
D --> A3["链路卡点<br>processFrame / BackPressure"]
D --> A4["回放分析<br>behind / 解压 / 累加器"]
A1 --> R["Report<br>同一份 AnalysisResult"]
A2 --> R
A3 --> R
A4 --> R
R --> H["report.html<br>echarts 可视化"]
R --> J["report.json<br>CI / 脚本消费"]三层解耦是这个结构的核心:Parser 和 Analyzer 解耦(同一份 ParsedData 被 4 个分析器独立消费),Analyzer 和 Report 解耦(AnalysisResult 同时喂 HTML 和 JSON),阈值全部外置到 rules.py(调参不改分析逻辑)。新增一个分析维度只需继承 BaseAnalyzer 实现 analyze(ParsedData) → AnalysisResult,配套 pytest 单测 9 个测试文件。
HCrash:IL2CPP 崩溃符号化向导
崩溃符号化的难点不在 addr2line 本身,而在「找到对的那版 so」。HCrash(WPF / .NET 8)把整条版本链做成四步向导,自动联动内部 CICD 和 Maven 制品仓库:
mermaid
flowchart LR
P["prop.txt"] --> R["CICD 查 ROM<br>得到 APK 版本"]
R --> B["Maven 拉 buildInfo<br>抽取 lib_napa5 版本"]
B --> SO["下载带符号 so<br>本地缓存复用"]
T["tombstone"] --> S["提取 libil2cpp.so<br>崩溃堆栈帧"]
S --> A["llvm-addr2line<br>还原源码行号"]
SO --> A
A --> OUT["符号化报告<br>导出 .md"]万能日志解密分析:三件套 + AI Skill
any_decrypt 递归解密 .xlog/.alog/.xp 并解压嵌套的 .zip/.7z/.gz(解密后内部还有加密的会继续解),支持 --dir_filter 按包名过滤加速;any_analyze 用 JSON 规则配置做场景化过滤(正则提取关键变量、多场景组合、内置网络/UI 路由等快捷场景),还能合并多份日志并顺带修复打印乱序。三个可执行文件覆盖 Win/Mac/Linux,Windows 侧支持拖动执行和右键菜单。
关键实现
脏数据是常态,不是异常。 高德 SDK 的 srTickTime 偶尔输出哨兵值 539976970008(约 539 亿毫秒),相邻回调间隔从正常的 100ms 暴涨到五千亿毫秒量级,echarts 折线图 Y 轴被撑爆,正常波动完全不可见。解法是数据分两条路走:间隔超过 10s 判为时钟跳变,图表里写 None 配合 connectNulls: false 画成断线(保人类可读),同时单独归类为 critical finding(保信息不丢失)。任何从外部系统拿到的数值,先假设它是脏的。
聚合优于罗列。 一份生产日志里 processFrame 超 10ms 出现了 1914 次,逐条生成 warning 就是 1914 行表格——这不是诊断,是对报告的 DDoS。规则是同类问题 5 条以内逐条显示、超过 5 条聚合为一条摘要(带次数和最大值)。唯一例外是 BackPressure(队列满丢帧),永远逐条输出,因为每次发生都代表真实数据丢失。
可读性是功能,不是装饰。 integrity 分析器曾把 150 多种 null texture 以原始 dict 形式 dump 进表格单元格,直接把报告布局撑爆。最后上了四层防御:分析器层只留 Top 10 且名字截断、detail 字段用结构化文本替代 raw dict、HTML 表格硬截 200 字符、CSS 层 max-width 兜底。哲学是不信任任何单一层——上游可能漏截,每层都独立防护。
先跑真实数据,再补合成测试。 V1 的单测全绿,但在真实数据上不可用:合成测试造不出 539 亿毫秒的哨兵值、造不出 90% 以上都是 0ms 的 processFrame、造不出 150 种 null texture。之后的实践变成:先跑真实生产日志人工审报告,把真实数据暴露的边界条件反向补进单测——比如 test_clock_jump_detected() 直接拿真实哨兵值当输入。合成测试验证逻辑正确性,真实数据验证设计合理性,缺一不可。
HCrash 的两个细节。 一是 load bias 自动检测:某些 ROM 里 tombstone 地址已是相对偏移,再减一次基址就全错了,工具自动判断要不要减。二是下载缓存:带符号的 libil2cpp.so 按版本缓存,重复分析不再下载。符号化失败的常见原因也收敛成了 FAQ——版本链某一步对错,堆栈就全是「??」。
从命令行到自然语言。 解密工具从 V4(命令行/右键/拖动三种执行方式)迭代到 V13(兼容非 16 字节对齐的 .xp 格式),中间修过 .xp 解压失败误删原文件、日志合并乱序、Linux 缺模块等一系列真实问题。最后一步是把它封装成 AI Skill 挂上内部技能市场:用自然语言说时间范围和想看的场景,Agent 自动更新工具、解密、过滤、给结论——UI 路由类问题有专门的调试 Skill,会先解密日志再专项分析。
指标
| 指标 | 改造前 | 改造后 |
|---|---|---|
| 车道级数据排查 | 人工翻日志 ≥30min,易遗漏 | 一键生成 HTML + JSON 双报告 |
| 诊断覆盖 | 凭经验,无固定套路 | 4 个正交维度,不可再分 |
| 阈值调参 | 散在正则、判断、文案三处 | rules.py 单文件集中管理 |
| 崩溃符号化 | 人工对版本、下符号表、跑 addr2line | 四步向导,版本链自动对齐 |
| 日志解密分析 | 手工解密嵌套包、人肉过滤 | 三端工具 + 规则化场景 + AI Skill |
复盘
- 诊断工具的价值不在「自动化」,在于分类体系。四个正交维度定对了,新故障进来自然有归属;定错了,工具越自动越误导。
- 面向人的输出必须做防御性设计:脏数据断线、长字段截断、无数据隐藏图表。图表为有意义的数据服务,不是为数据服务。
- 阈值外置 + 基类插件化 + pytest,这三件事让工具从「个人脚本」变成「团队资产」——新同事打开 rules.py 就能看到全部诊断阈值的全局视图。
- 工具的终局是被 AI 调用。命令行参数设计得越规整,封装成 Skill 的成本越低;V13 的迭代里有一半修复都来自真实用户的真实日志,这比任何设计评审都有效。
- HCrash 后来接进了 飞书 CLI Agent 成为 17 类指令之一,崩溃分析从「打开软件点四步」变成「群里发一句话」。