Skip to content

监控上报链路搭建 ​

从 0 到 1 打通 Unity → Android 原生 → 后台监控平台 → 飞书告警的完整链路:端上四层架构保证主线程不被监控拖慢,10 段链路每一段都有日志签名可定位断点,配额限流防止告警风暴。

业务 Monitor14 个
上报链路10 段
配额限流10 次/天 + 100KB/天
告警时延crash 后 5 分钟

背景 ​

小鹏一张图的线上质量数据(crash、卡顿、性能、信号异常)需要从车机采集 → 上报 → 后台聚合 → 飞书通知 → 开发可查阅。6.0.0 版本之前,这条链路不存在——线上问题要等用户反馈才知道,SR 黑屏卡死这类问题在用户嘴里是「导航死了」,没有任何可分析的数据。

问题 ​

  1. 车机不是服务器:监控逻辑跑在渲染主线程边上,采集一重就把帧率拖垮,监控自己成了被监控对象。
  2. 上报量必须可控:线上几万台车,一个误判的异常就能把后台和告警群刷爆。
  3. 链路长、断点多:从 Unity C# 到 Android Java 到 MQTT 到后台索引,任何一段静默失败,表现都是「监控网站查无此条」。

方案 ​

端上四层架构 ​

层级模块职责
L1 业务层各业务 Service在关键点调用采集接口
L2 监控层各 XXXMonitor轻量采集 + 定时分析 + 组装报告
L3 框架层ExceptionMonitor后台线程调度 + 配额管理 + 本地日志
L4 传输层MonitorManagertag→type 映射 + JSON 包装 + 发 Android

核心纪律(和异步日志同源):主线程只做轻量采集(计数/滑窗/固定队列/快照,禁止字符串拼接和堆栈采样),后台线程按 sample_time 周期做分析,命中才组装报告,统一走 SaveException 出口——本地日志必写,落盘可选,上报 Android 受配额和开关控制。

全链路 10 段 ​

mermaid
flowchart LR
    A["Monitor 异常触发<br>OnException"] --> B["SaveException<br>本地日志 + 配额判断"]
    B --> C["MonitorManager<br>tag→type 映射 + JSON"]
    C --> D["Unity→Android 桥<br>消息 ID 1050"]
    D --> E["MonitorService<br>按 type 限流"]
    E --> F["DataLogDelegate<br>Handler 切线程"]
    F --> G["构造 MoleEvent<br>+ 公共参数注入"]
    G --> H["MQTT 通道<br>xmart:cdu:data:VIN"]
    H --> I["主动监控平台<br>索引延迟 5-30min"]
    I --> J["Web 查询 +<br>飞书异常告警"]

每一段都有日志签名:Unity 侧看 SendExceptionReportToAndroid: type=...,桥接看 SendUnityMsg : 1050,Android 侧看 report accepted,MQTT 看 internalSend,200。排查时按链路从前到后 grep,最后一个有日志的节点的下一跳就是断点——「上有下无」一定对应一个具体根因。

端上全通之后还有后台一关:事件要在主动监控平台注册白名单,带灰度/debug 后缀的包版本会被过滤,desc 含测试关键字会被黑词拦截,同一用户同一事件高频上报会触发反作弊,索引本身还有 5-30 分钟延迟。联调时「端上全 OK 但网站查无」基本就是这五种情况之一。

配额与闸门 ​

  • 配额:按 tag 维度 10 次/天 + 100KB/天,超限静默丢弃(只在 DebugLog 里可见),跨天自动重置。设计建议是每类异常一天只报一次,带足上下文。
  • 七道闸门:Monitor 的 Active 开关、Report 开关(启动约 2 分钟内默认不上报)、本地落盘开关、配额、Android 转发总开关(ADB 可翻转)、ROM 类型(USERDEBUG 不上报)、tag→type 注册表。任何一道关着,数据就到不了 Android。
  • 兜底:本地 XLog 日志不受配额影响,超限了至少本地还有。

关键实现 ​

两处真实缺陷修复 ​

缺陷 1:上报内容变成对象哈希(620 版本监控失效)。线上发现后台收到的 desc 字段全是 XDataPropertyValue@1a2b3c 这样的对象哈希而不是 JSON——Android 侧解包信号时漏取 .value,整包被 toString() 了。后果是 620 版本监控上报实质失效:异常类型解析全部落入 UNKNOWN 桶,限流计数也不按类型分桶。修复解包逻辑后,620 版本缺陷闭环,合入 6.2.0/6.2.2。这个缺陷的教训直接写进了排查手册:端上每一段都「成功」,不代表数据是对的,必须抽查上报内容本身。

缺陷 2:限流策略与联调冲突。生产限流同 type 每天 10 次,压测时 10 次打满后链路「看起来断了」,排查半天是期望行为。后来给测试包单独放宽到 100 次(cherry-pick 专用 commit,不合入主线),并在手册里把「reach max daily report count」标注为正常日志而非故障。

6.0.0 落地的 14 个 Monitor ​

帧率、内存、行车障碍物、LD 行车障碍物、泊车障碍物、泊车位数据、AP 占据格、可走面、LD 引导线/可走面、车道线、行车消息耗时、消息全路径耗时、占据格消息耗时、状态监控。判定标准对齐产品体感:画面冻结、帧率、tile 空白、可走面/可走线缺失、内存异常、脚本异常——监控项是从「产品接受不了什么」倒推出来的,不是从技术能采什么正推的。

指标 ​

指标采集方式告警阈值
Crash 率Unity Exception Handler> 0.1%/日
帧率每 5 分钟采样< 30fps
GPU 占用Android GPU Inspector> 80%
内存Unity Profiler API> 500MB
卡顿主线程超时检测> 200ms
  • 620 版本监控上报失效缺陷闭环(合入 6.2.0/6.2.2)。
  • 线上问题从「用户反馈才知道」变成「crash 后 5 分钟飞书通知」,告警带车型、版本、异常概要,可一键认领/忽略。
  • 14 个业务 Monitor 覆盖数据、性能、稳定性三类异常,接入有 SOP:新增 Monitor 必须注册 tag→type 映射,否则上报会被打到默认桶归错类。

复盘 ​

  1. 监控系统的第一需求是「别影响业务」。主线程轻量采集、后台分析、统一出口这三条纪律,比任何单个 Monitor 的判定逻辑都重要。
  2. 静默丢弃一定要有旁路可见性。配额超限不打 warn 是防刷屏的正确设计,但没有 DebugLog 旁路的话,联调会被自己的限流骗到。
  3. 长链路靠日志签名排查,不靠猜。10 段链路每段一个 grep 关键字,断点定位从半天缩到十分钟。
  4. 先修链路,再信数据。620 版本「监控没报异常」一度被解读为「质量变好」,实际是上报失效——监控自己的健康度也要被监控。

罗子初 · AI 座舱专家 · 8年端侧研发

Lv.1