27、Logcat 在 CI/CD 中的应用:自动化日志收集与问题预警
说实话,很多团队做 CI/CD,跑完自动化测试就算完事了。日志呢?要么没人看,要么等用户反馈了才去翻。这其实挺可惜的。我个人习惯是把 Logcat 当成一个「哨兵」,让它自动盯着流水线里的每一个构建和测试环节。
今天我们就聊聊,怎么把 Logcat 塞进 CI/CD 流程里,让它自动收集日志,还能在出问题的时候提前报警。
为什么要在 CI/CD 里用 Logcat?
你想想看,本地开发的时候,Logcat 就在 Android Studio 底下滚着,出问题一眼就能看到。但到了 CI 环境,没有屏幕,没有鼠标,Logcat 默认是关掉的。很多隐蔽的运行时异常、ANR 前兆、内存泄漏的蛛丝马迹,就这么被忽略了。
我在项目中遇到过好几次:本地测试全绿,CI 也全绿,结果灰度一上,用户疯狂崩溃。后来一查,是某个低端机在 CI 上跑的时候 Logcat 里早就打印了 OutOfMemoryError 的堆栈,但没人去看。从那以后,我就把「自动收集 Logcat」写进了每个项目的 CI 脚本里。
自动化收集:从命令行开始
CI 环境里没有 Android Studio,但我们有 adb logcat。核心思路很简单:在测试执行的同时,启动一个后台进程抓取日志,测试结束后保存成文件。
下面是我常用的一个脚本片段,放在 Jenkins 或 GitLab CI 的 before_script 里:
#!/bin/bash
# 启动 logcat 后台抓取
adb logcat -v threadtime -b all > build_${BUILD_NUMBER}.log &
LOGCAT_PID=$!
echo "Logcat PID: $LOGCAT_PID"
# 运行测试(示例)
./gradlew connectedDebugAndroidTest
# 测试结束后,等待 2 秒确保日志刷完
sleep 2
kill $LOGCAT_PID
echo "日志已保存到 build_${BUILD_NUMBER}.log"
-b all 参数,把 main、system、events、crash 四个缓冲区都抓下来。有些 ANR 信息只在 events 缓冲区里出现,只抓 main 会漏掉关键线索。
问题预警:从日志里挖出「地雷」
光收集还不够,得让机器帮我们看。说白了,就是在日志里搜索那些「不该出现」的关键词。
我总结了一个高频预警关键词表,你可以直接拿来用:
| 关键词 | 含义 | 预警级别 |
|---|---|---|
FATAL EXCEPTION |
未捕获的崩溃 | 严重 |
ANR in |
应用无响应 | 严重 |
OutOfMemoryError |
内存溢出 | 严重 |
NullPointerException |
空指针异常 | 高 |
ClassNotFoundException |
类找不到(常见于混淆问题) | 高 |
Could not read input channel |
输入通道异常(可能卡顿) | 中 |
BufferOverflowException |
缓冲区溢出 | 中 |
在 CI 脚本里,我们可以用 grep 配合退出码来做预警:
#!/bin/bash
LOG_FILE="build_${BUILD_NUMBER}.log"
# 检查严重错误
if grep -q "FATAL EXCEPTION\|ANR in\|OutOfMemoryError" "$LOG_FILE"; then
echo "❌ 检测到严重错误!请立即查看日志。"
# 这里可以触发钉钉/飞书/邮件通知
exit 1
fi
# 检查高优先级警告
if grep -q "NullPointerException\|ClassNotFoundException" "$LOG_FILE"; then
echo "⚠️ 发现高优先级异常,建议人工审查。"
# 可以标记构建为 unstable,但不阻断
fi
echo "✅ 日志检查通过,未发现严重问题。"
知识体系:Logcat 在 CI/CD 中的完整链路
下面这张图,是我自己画的一个流程框架。它把日志收集、解析、预警、归档串在了一起。你可以直接照着这个结构去搭建你的 CI 流水线。
实战中的几个坑
嗯,这里我要多说几句。自动化日志收集看着简单,但实际落地的时候,有几个地方特别容易翻车。
- 日志文件太大:一个完整的 UI 自动化测试跑下来,Logcat 可能生成几百 MB 的文本。我建议在抓取时加上
-G 20M限制缓冲区大小,或者用grep实时过滤,只保留 Warning 及以上级别的日志。 - adb 连接不稳定:CI 机器上如果同时跑多个模拟器,adb 可能会掉线。我习惯在脚本里加一个重试逻辑:如果
adb logcat命令失败,等 3 秒再试一次。 - 时间戳对齐:Logcat 的时间戳是设备本地时间,CI 服务器可能是 UTC。如果你需要把日志和测试用例的执行时间对应起来,建议在测试开始和结束时各打一条标记日志,比如
Log.d("CI_MARKER", "TEST_START")。
我个人觉得,这套方案最大的价值不是「收集」,而是「预警」。当你的 CI 脚本能在凌晨三点自动发出一条「检测到 ANR 趋势上升」的消息时,你就知道,之前花在搭建上的时间,全都值回来了。