从“日志抓不到”到“全链路可追溯”:一次 Android 系统级日志体系的工程化实践

30 阅读3分钟

从“日志抓不到”到“全链路可追溯”:一次 Android 系统级日志体系的工程化实践

——一个高级工程师如何把“运维痛点”落地成“系统能力”


一、问题背景:为什么我们要“重新造日志体系”?

在实际项目中,我们经常会遇到这样的问题:

  • 问题难复现:客户现场偶发问题,回传日志不完整

  • Kernel / Logcat / 网络日志割裂:信息分散,无法关联分析

  • 日志不可控

    • 一直开 → 占空间、影响性能
    • 关了 → 出问题没数据
  • tcpdump 需要人工介入,现场操作成本高

结论

不是“日志不够多”,而是日志体系缺乏工程化设计

于是需求就变成了一句话:

在不影响系统稳定性的前提下,构建一套可开关、可轮转、可统一管理的系统级日志采集方案。


二、需求拆解:高级工程师是如何“拆问题”的?

我习惯把需求拆成 4 个维度

1️⃣ 日志类型维度

类型目的
logcatFramework / App 问题
kernel驱动 / 底层异常
tcpdump网络问题定位

2️⃣ 生命周期维度

  • 开机是否自动准备环境?
  • 是否支持 运行期动态开关
  • 是否随 reboot 清理?

3️⃣ 资源控制维度

  • 单文件大小限制
  • 文件数量限制
  • tmpfs / data 分层使用

4️⃣ 可运维维度

  • Property 控制
  • 无需 adb 介入
  • 出厂默认关闭,问题时开启

高级工程师不会一上来写代码,而是先把“系统行为”想清楚。


三、整体架构设计:不是脚本,而是“系统能力”

🧱 架构总览

┌──────────────┐
│ Android init │
└──────┬───────┘
       │ property trigger
┌──────▼────────────────────────┐
│ logcatd.rc                     │
│                                │
│ ├─ logcatlog.sh   (logcat)     │
│ ├─ kernel.sh      (dmesg -w)   │
│ └─ tcpdump.sh     (pcap)       │
└──────┬────────────────────────┘
       │
┌──────▼──────────┐
│ /data/log/tmp   │  ← tmpfs
│  logcat / kernel│
│  tcpdump pcap   │
└─────────────────┘

🎯 关键设计决策

决策原因
使用 init.rc + property系统级、稳定、无需 daemon 常驻
使用 shell 脚本易维护、快速定制
tmpfs防止 flash 写爆
oneshot service + while可控、避免 init 重启风暴

四、技术原理拆解(核心干货)

1️⃣ 为什么不用原生 logcatd?

  • logcatd:

    • 强耦合 logd
    • 配置复杂
    • 不适合动态 TAG / 网络日志

结论
👉 logcat 是工具,logcatd 是系统组件,不要滥用


2️⃣ kernel 日志为什么用 dmesg -w

dmesg -w >> kernel.log

优势:

  • 实时
  • 不依赖 logd
  • 崩溃前最后信息也能抓到

配合:

  • 文件大小监控
  • kill + 轮转
  • property 动态关闭

3️⃣ tcpdump 为什么用 init service?

on property:persist.sys.emdoor.tcpdump=1
    start tcpdump_all

好处:

  • 避免后台常驻
  • 权限天然是 root
  • 行为可审计(property)

这是系统工程思维,而不是运维脚本思维。


4️⃣ 为什么要“自己写轮转”?

原因很现实:

  • busybox logrotate 不一定存在
  • Android shell 功能受限
  • 要可控、可定制

所以用最原始、最可靠的方式:

stat -c %s
mv log log.1

高级工程师不追求优雅,追求确定性。


五、编码层面的工程经验总结(非常重要)

✅ 1. init service 一定要 oneshot + while

❌ 错误示范:

service xxx /system/bin/xxx.sh

一旦脚本退出 → init 无限重启

✅ 正确方式:

service xxx /system/bin/xxx.sh
    oneshot

✅ 2. 永远用 property 控制行为,不用 kill -9

ENABLE=$(getprop persist.logcat.enable)
  • 可远程控制
  • 可持久化
  • 可追溯

✅ 3. tmpfs 是日志工程的“护城河”

mount tmpfs tmpfs /data/log/tmp

好处:

  • 不伤 flash
  • 重启自动清空
  • 适合问题分析日志

✅ 4. Android.bp 用 prebuilt_binary 很关键

cc_prebuilt_binary {
    name: "logcatlog.sh",
}
  • 不编译
  • 不引入 toolchain 问题
  • 升级风险极低

六、从“写功能”到“做系统”的思维跃迁

很多工程师会问:

“这不就是几个 shell 脚本吗?”

但真正的差别在于:

初级思维高级工程思维
能不能跑能不能长期稳定跑
写脚本构建系统能力
临时抓日志可运维、可交付
解决一次问题降低 N 次问题成本

七、结语:日志不是辅助功能,而是系统的“黑匣子”

当系统复杂到一定程度:

日志能力 = 系统可维护性

转载请注明出处juejin.cn/spost/75984…