第三讲:日志格式解析——常见的电池日志格式

大家好,欢迎来到第三讲。上一讲我们聊了日志采集的工具链,今天咱们来点实在的——拿到日志之后,怎么读懂它?

说实话,我见过不少工程师,采集日志时头头是道,一打开文件就懵了。满屏的十六进制、时间戳、状态码……嗯,这很正常。我自己刚入行那会儿,对着 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 里会有锁的名称和时长。
我的小技巧: 解析 BatteryHistorian 日志时,我通常会先写一个 Python 脚本,把 JSON 里的所有事件类型列出来。这样一眼就能看出日志里包含了哪些信息,避免遗漏关键数据。

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」是它的子项,解析时要注意缩进或空行。
避坑指南: 我曾经在解析 dumpsys 输出时,忽略了空行和注释行,结果把「Estimated battery capacity」后面的数字当成了电池电量,闹了个笑话。所以,解析前一定要先看看原始数据的结构,把无关行过滤掉。

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。我一般用 pandasdropna() 或者 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 的详细字段解析,到时候我会带你手把手写一个解析脚本。咱们下期见。