第三讲:日志格式解析——常见的电池日志格式
大家好,欢迎来到第三讲。上一讲我们聊了日志采集的工具链,今天咱们来点实在的——拿到日志之后,怎么读懂它?
说实话,我见过不少工程师,采集日志时头头是道,一打开文件就懵了。满屏的十六进制、时间戳、状态码……嗯,这很正常。我自己刚入行那会儿,对着 BatteryHistorian 的 JSON 文件看了半小时,愣是没找到电池电量在哪一行。
所以这一讲,我就把三种最常见的电池日志格式掰开揉碎了讲给你听。分别是:BatteryHistorian 格式、dumpsys batterystats 格式,以及自定义 CSV 格式。每种我都会给出解析思路和实战技巧。
3.1 BatteryHistorian 格式
BatteryHistorian 是 Google 官方推出的电池分析工具。它的日志格式说白了就是一个 JSON 文件,结构非常清晰。
我习惯把它比作「电池事件的流水账」。每一行记录一个事件,比如「屏幕亮了」、「Wi-Fi 断了」、「CPU 频率变了」等等。
来看一个典型的片段:
{
"version": 1,
"entries": [
{
"time": 1234567890,
"type": "power_use_summary",
"data": {
"battery_level": 85,
"screen_on": true,
"wifi_on": false,
"cpu_usage": 12.5
}
},
{
"time": 1234567895,
"type": "state_change",
"data": {
"from": "screen_on",
"to": "screen_off"
}
}
]
}
你看,每个 entry 都有三个字段:time(时间戳)、type(事件类型)、data(具体数据)。
解析要点:
- 时间戳:通常是 Unix 时间戳(秒级或毫秒级)。我建议你第一时间把它转成可读的日期格式,否则看着一堆数字容易晕。
- 事件类型:常见的有
power_use_summary(电量汇总)、state_change(状态变化)、wakelock(唤醒锁)等。 - data 字段:不同事件类型对应的数据结构不同。比如
power_use_summary里会有电池电量、屏幕状态等;wakelock里会有锁的名称和时长。
3.2 dumpsys batterystats 格式
dumpsys batterystats 是 Android 系统自带的电池统计工具。它的输出格式是纯文本,看起来比 JSON 要「糙」一些,但信息量非常大。
我记得第一次跑这个命令时,终端里刷出了几百行数据,我整个人都傻了。后来慢慢摸清了规律,其实它主要分为几个大块:
- 统计概览:电池容量、剩余电量、充电状态等。
- 各模块耗电排行:屏幕、Wi-Fi、蜂窝网络、CPU 等分别耗了多少电。
- 唤醒锁统计:哪些应用持有了唤醒锁,持有了多久。
- 进程统计:每个进程的 CPU 使用时间、网络流量等。
一个典型的输出片段:
Estimated battery capacity: 4000 mAh
Screen on: 2h 15m 30s
Wi-Fi: 1h 45m 20s
CPU usage: 45m 12s
App: com.example.app
Wake lock: MyWakeLock held for 30m 15s
CPU time: 12m 30s
Network: 150 MB received, 20 MB sent
解析要点:
- 文本解析:因为是纯文本,所以你需要用正则表达式或者字符串分割来提取数据。我个人习惯用 Python 的
re模块,匹配关键字段。 - 时间格式:注意时间可能是
2h 15m 30s这种格式,需要转成统一的秒数方便计算。 - 层级关系:比如「App」下面的「Wake lock」是它的子项,解析时要注意缩进或空行。
3.3 自定义 CSV 格式
很多时候,我们采集的日志并不是标准格式,而是自己定义的 CSV 文件。比如我参与的一个 IoT 项目,设备每 10 秒上报一次数据,格式就是 CSV:
timestamp, battery_level, temperature, current_ma, voltage_mv
2025-01-15 10:00:00, 85, 25.3, 120, 3800
2025-01-15 10:00:10, 84, 25.4, 130, 3795
2025-01-15 10:00:20, 84, 25.5, 125, 3790
CSV 格式的好处是简单、直观,用 Excel 就能打开。但坏处也很明显——字段含义全靠约定,一旦有人改了列名或者顺序,解析脚本就废了。
解析要点:
- 表头检查:我建议你在解析 CSV 时,先读取第一行作为表头,然后动态映射列索引。这样即使列顺序变了,代码也能自适应。
- 数据类型转换:CSV 里所有数据都是字符串,你需要手动转成 float 或 int。比如
battery_level是整数,current_ma是浮点数。 - 缺失值处理:有时候设备上报会丢数据,CSV 里可能出现空行或者
NaN。我一般用pandas的dropna()或者fillna()来处理。
3.4 三种格式的对比
为了让你更直观地理解,我做了一个对比表:
| 特性 | BatteryHistorian | dumpsys batterystats | 自定义 CSV |
|---|---|---|---|
| 格式 | JSON | 纯文本 | CSV |
| 可读性 | 中等(需解析) | 较低(信息密集) | 高(Excel 可看) |
| 信息量 | 大(事件级) | 极大(系统级) | 自定义(灵活) |
| 解析难度 | 低(有库支持) | 中(需正则) | 低(pandas 搞定) |
| 适用场景 | Google 工具链 | Android 系统调试 | 嵌入式设备采集 |
你想想看,如果你手头是 Android 手机,用 dumpsys 最方便;如果是自己做的 IoT 设备,CSV 最灵活;如果想用 BatteryHistorian 做可视化,那就得解析 JSON。
3.5 实战建议
最后,我分享几个实战中的小经验:
- 先看样本数据:拿到日志后,别急着写解析代码。先打开文件看几行,了解它的结构和特点。我一般会用
head -20或者more命令预览。 - 写一个通用的解析器:我建议你写一个 Python 类,把三种格式的解析逻辑封装起来。输入是文件路径,输出是统一的 DataFrame。这样后续分析代码就不用改了。
- 注意时区:时间戳有时是 UTC,有时是本地时间。我踩过这个坑——有一次分析日志,发现电量变化曲线对不上,最后发现是时区没统一。所以,解析时一定要明确时区,最好统一转成 UTC。
好了,这一讲就到这里。三种格式的解析方法你都掌握了,下一讲我们会深入 BatteryHistorian 的详细字段解析,到时候我会带你手把手写一个解析脚本。咱们下期见。