第42章:日志收集与分析:bugreport、dumpsys、logcat组合、自动化分析脚本
说到Android系统调试,日志就是我们的眼睛。没有日志,你就像在黑夜里摸路,全靠运气。我个人习惯是,拿到一个系统问题,第一件事就是拉日志。但拉日志也有讲究,不是随便抓一把就能看出门道的。
今天咱们聊聊三个核心工具:bugreport、dumpsys、logcat。以及怎么把它们组合起来,再配上自动化脚本,让分析效率翻倍。
42.1 bugreport:系统全貌的快照
bugreport 是什么?说白了,它就是系统当前状态的“全家福”。把系统所有关键信息打包成一个文件,包括日志、进程状态、内存信息、网络状态等等。
我遇到过不少同事,一上来就只抓 logcat,结果问题涉及系统服务状态,logcat 里根本看不出。这时候 bugreport 就派上用场了。
基本用法
# 抓取 bugreport
adb bugreport
# 指定输出路径
adb bugreport /path/to/save/
# 抓取并直接解压查看
adb bugreport bugreport.zip
执行后,你会得到一个 zip 包。解压后里面包含:
- bugreport-xxx.txt:核心报告,文本格式
- dumpstate_log.txt:dumpstate 的详细日志
- logcat.txt:当前 logcat 缓冲区内容
- kernel.log:内核日志
- events.log:事件日志
grep 或 findstr 先过滤关键信息,而不是直接打开全文。比如搜索 "FATAL EXCEPTION"、"ANR"、"crash" 等关键词。
42.2 dumpsys:系统服务的诊断利器
dumpsys 可以查看系统服务的内部状态。它比 bugreport 更灵活,你可以只 dump 你关心的服务。
举个例子,如果怀疑是内存泄漏,我会先 dump 内存信息:
# 查看所有可用服务
adb shell dumpsys -l
# 查看内存信息
adb shell dumpsys meminfo
# 查看某个进程的内存
adb shell dumpsys meminfo com.android.systemui
# 查看 Activity 栈
adb shell dumpsys activity activities
# 查看窗口信息
adb shell dumpsys window windows
我曾经遇到一个诡异的问题:应用启动后界面卡住,但 logcat 里没有任何异常。后来我用 dumpsys activity activities 一看,发现 Activity 栈里有个奇怪的 Fragment 卡在中间,导致界面无法正常显示。嗯,这种问题光靠 logcat 是抓不到的。
常用 dumpsys 服务一览
| 服务名 | 用途 | 典型场景 |
|---|---|---|
| meminfo | 内存使用详情 | 内存泄漏、OOM |
| activity | Activity 栈、任务栈 | 界面跳转异常、启动卡顿 |
| window | 窗口层级、焦点 | 窗口遮挡、触摸无响应 |
| cpuinfo | CPU 使用率 | 性能瓶颈、高负载 |
| battery | 电池状态、耗电统计 | 异常耗电、充电问题 |
| netstats | 网络流量统计 | 后台流量异常 |
| package | 包信息、权限 | 安装失败、权限问题 |
42.3 logcat:实时日志的王者
logcat 是大家最熟悉的工具了。但你真的会用吗?
我见过很多人直接 adb logcat 然后盯着屏幕看,信息刷得飞快,根本抓不住重点。其实 logcat 有很多过滤技巧。
高效过滤
# 按标签过滤
adb logcat -s TAG_NAME
# 按优先级过滤(V/D/I/W/E/F)
adb logcat *:E
# 组合过滤
adb logcat -s TAG_NAME:E
# 按进程 PID 过滤
adb logcat --pid=1234
# 保存到文件
adb logcat -v threadtime > logcat.txt
我个人最常用的是 -v threadtime 格式,它会把时间、线程 ID、进程 ID 都显示出来,方便后续分析。
缓冲区管理
logcat 有多个缓冲区,默认只抓 main 和 system。但有些日志会写到 events 或 crash 缓冲区。
# 查看所有缓冲区
adb logcat -b all
# 只抓 crash 缓冲区
adb logcat -b crash
# 清空缓冲区(抓取前清空,避免干扰)
adb logcat -c
42.4 三剑客组合:bugreport + dumpsys + logcat
单独用每个工具都有局限。组合起来,才能看到全貌。
我的标准流程是这样的:
- 先抓 bugreport:获取系统快照,包括所有服务的状态
- 再抓 dumpsys:针对怀疑的服务,深入查看内部状态
- 最后抓 logcat:实时监控,捕捉问题发生时的日志
举个例子,分析一次 ANR:
# 1. 抓取 bugreport(包含 ANR 时的系统状态)
adb bugreport
# 2. 查看 ANR 相关的服务状态
adb shell dumpsys activity processes
adb shell dumpsys window policy
# 3. 实时抓取 logcat,过滤 ANR 相关日志
adb logcat -b events -s am_anr
adb logcat -b main -s ActivityManager:I
这样组合下来,你既能知道 ANR 发生时系统在做什么,又能看到具体的调用栈和日志信息。
42.5 自动化分析脚本
手动分析日志太慢了。尤其是 bugreport 动辄几十 MB,人工翻找效率极低。我写了一些脚本来自动化分析。
Python 脚本示例:提取关键信息
import re
import sys
def parse_bugreport(filepath):
"""解析 bugreport,提取关键信息"""
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
# 提取 ANR 信息
anr_pattern = r'ANR in (.*?)\n'
anrs = re.findall(anr_pattern, content)
# 提取崩溃信息
crash_pattern = r'FATAL EXCEPTION: (.*?)\n'
crashes = re.findall(crash_pattern, content)
# 提取内存信息
mem_pattern = r'Total RAM: (.*?)\n'
mem_info = re.findall(mem_pattern, content)
return {
'anrs': anrs,
'crashes': crashes,
'memory': mem_info
}
if __name__ == '__main__':
result = parse_bugreport(sys.argv[1])
print(f"发现 {len(result['anrs'])} 个 ANR")
print(f"发现 {len(result['crashes'])} 个崩溃")
print(f"内存信息: {result['memory']}")
Shell 脚本:一键抓取并分析
#!/bin/bash
# 一键抓取日志并分析
# 设置时间戳
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_DIR="logs_$TIMESTAMP"
mkdir -p $LOG_DIR
# 抓取 bugreport
echo "抓取 bugreport..."
adb bugreport $LOG_DIR/bugreport.zip
# 抓取 dumpsys
echo "抓取 dumpsys..."
adb shell dumpsys meminfo > $LOG_DIR/meminfo.txt
adb shell dumpsys activity activities > $LOG_DIR/activities.txt
adb shell dumpsys window windows > $LOG_DIR/windows.txt
# 抓取 logcat
echo "抓取 logcat..."
adb logcat -v threadtime -d > $LOG_DIR/logcat.txt
# 分析 ANR
echo "分析 ANR..."
grep -i "anr" $LOG_DIR/logcat.txt > $LOG_DIR/anr_analysis.txt
# 分析崩溃
echo "分析崩溃..."
grep -i "fatal" $LOG_DIR/logcat.txt > $LOG_DIR/crash_analysis.txt
echo "日志已保存到 $LOG_DIR"
42.6 知识体系总览
下面这张图总结了日志收集与分析的核心流程:
从图中可以看到,三个工具各有侧重,组合起来才能覆盖大部分调试场景。再加上自动化脚本,就能从海量日志中快速定位问题。
42.7 实战经验总结
最后分享几点我踩过的坑:
- 不要只依赖一种日志:bugreport 看不到实时变化,logcat 看不到系统状态,dumpsys 看不到历史记录。三者互补才是王道。
- 日志要有时序:我习惯在日志里加上时间戳,这样能还原问题发生的时间线。logcat 的
-v threadtime就是为此设计的。 - 自动化要适度:脚本能帮你过滤 80% 的噪音,但剩下 20% 的关键判断还是得靠人。别完全相信脚本的输出,要自己验证。
- 保存原始日志:分析完后,原始日志别急着删。有时候回头看,会发现之前忽略的线索。
嗯,日志分析这事,说白了就是经验活。工具就这些,但怎么用、什么时候用、怎么组合,全靠实战积累。多抓几次 bugreport,多看看 dumpsys 的输出,慢慢你就能一眼看出问题在哪了。