4、日志采集工具:ADB日志抓取、串口日志捕获、远程日志收集方案
做智能音箱的故障诊断,说白了就是跟日志打交道。日志拿不到,或者拿不全,后面所有分析都是瞎猜。我这些年经手过的项目,从早期的Linux小盒子到现在的Android智能音箱,日志采集这块踩过的坑真不少。今天就把三种最常用的方案掰开揉碎讲清楚。
4.1 ADB日志抓取:Android音箱的标配
现在市面上绝大多数智能音箱跑的都是Android系统。ADB(Android Debug Bridge)就是咱们最趁手的工具。我个人习惯,拿到一台新音箱,第一件事就是连上ADB试试水。
4.1.1 基础抓取命令
先说说最常用的几个命令。你想想看,音箱出问题了,第一反应肯定是看系统日志。
# 抓取所有日志,输出到文件
adb logcat -v threadtime > bugreport.log
# 按优先级过滤:只显示Error及以上级别
adb logcat *:E
# 按标签过滤:只看WiFi相关的日志
adb logcat -s WifiManager
# 清空缓冲区,重新开始抓取
adb logcat -c
嗯,这里要注意一个细节。很多新手上来就adb logcat,结果日志刷得飞快,根本来不及看。我建议加上-v threadtime参数,这样每条日志都带时间戳和线程ID,排查问题时能精确到毫秒级。
4.1.2 抓取特定进程的日志
有一次我在项目现场排查问题,音箱的语音唤醒功能时好时坏。系统日志刷得眼花缭乱,根本找不到关键信息。后来我用了按进程ID过滤的方法,一下子就锁定了问题。
# 先找到目标进程的PID
adb shell ps | grep voice
# 假设PID是1234,只抓这个进程的日志
adb logcat --pid=1234 -v threadtime
这样做的好处很明显——排除干扰,直击要害。我建议你在调试特定功能时,优先用这个方法。
4.1.3 抓取内核日志
有些底层问题,比如驱动崩溃、内存异常,用户空间的日志根本看不到。这时候就得看内核日志了。
# 抓取内核日志
adb shell dmesg > kernel.log
# 实时监控内核日志
adb shell dmesg -w
我曾经遇到过一个音箱频繁重启的问题,应用层日志一切正常,但dmesg里清清楚楚地写着Out of memory: killed process。说白了,就是内存泄漏把系统搞崩了。
4.2 串口日志捕获:底层调试的救命稻草
ADB虽然方便,但有个致命弱点——系统必须能正常启动。如果音箱卡在开机阶段,或者内核直接panic了,ADB根本连不上。这时候,串口就是最后的希望。
4.2.1 硬件连接
串口调试需要硬件支持。大多数智能音箱的主板上都预留了串口焊盘,一般是3.3V电平的UART接口。你需要准备一个USB转串口工具,比如FT232或者CH340。
接线方式很简单:
- GND:地线,必须接
- TX:音箱发送,接工具的RX
- RX:音箱接收,接工具的TX
- VCC:一般不用接,串口是独立供电的
4.2.2 串口工具配置
Windows上我习惯用PuTTY或者SecureCRT,Linux下直接用screen或者minicom。波特率一般是115200,但也有用921600的,具体看芯片手册。
# Linux下使用screen连接串口
sudo screen /dev/ttyUSB0 115200
# 退出screen:Ctrl+A,然后按K
嗯,这里有个坑。有些USB转串口工具在Linux下需要装驱动,否则识别不出来。我建议你提前在开发机上装好ch341或者ftdi_sio驱动。
4.2.3 抓取启动日志
串口最大的价值,就是能看到从uboot开始的完整启动过程。我遇到过一台音箱,开机后屏幕一直黑着。ADB连不上,串口一接上去,日志显示DRAM initialization failed——内存初始化失败,硬件问题。
# 将串口日志保存到文件(Linux)
sudo cat /dev/ttyUSB0 > serial_boot.log
# 或者用screen自带的日志功能
screen -L -Logfile serial.log /dev/ttyUSB0 115200
我个人习惯,每次拿到新设备,都会用串口抓一次完整的启动日志保存下来。这样以后出问题了,可以对比着看,哪里变了就一目了然。
4.3 远程日志收集方案:量产后的运维利器
前面两种方法都要求设备在本地,能物理接触。但音箱一旦量产发货到用户家里,出了问题怎么办?总不能让人家寄回来吧。这时候就需要远程日志收集方案了。
4.3.1 日志上传到云端
最常用的方案,是在音箱固件里集成一个日志上传模块。当检测到异常时,自动打包日志上传到云端服务器。
# 伪代码示例:日志上传模块
def upload_logs():
# 打包日志文件
log_files = ["/data/logs/system.log",
"/data/logs/crash.log",
"/data/logs/network.log"]
# 创建tar包
tar_cmd = "tar -czf /tmp/logs.tar.gz " + " ".join(log_files)
os.system(tar_cmd)
# 上传到云端
upload_url = "https://log-collector.example.com/upload"
upload_file("/tmp/logs.tar.gz", upload_url)
这里要注意几个问题:
- 日志大小控制:用户家的网络可能很慢,日志包不能太大。我一般限制在5MB以内,超过就截断。
- 上传时机:别在音箱播放音乐时上传,会影响用户体验。我建议在待机或者深夜自动上传。
- 隐私保护:日志里不能包含用户语音数据或者WiFi密码。这个一定要做过滤,否则会出大问题。
4.3.2 远程ADB方案
有些高端音箱支持远程ADB调试,说白了就是通过网络转发ADB端口。这样工程师坐在办公室,就能像操作本地设备一样调试远程音箱。
# 在音箱上启动ADB网络服务
adb tcpip 5555
# 从远程电脑连接(假设音箱IP是192.168.1.100)
adb connect 192.168.1.100:5555
# 连接成功后,所有ADB命令照常使用
adb logcat -v threadtime
4.3.3 日志轮转策略
日志不能无限增长,否则会把存储空间撑爆。我建议在固件里实现日志轮转机制。
| 日志类型 | 保留数量 | 单个文件大小 | 说明 |
|---|---|---|---|
| 系统日志 | 5个 | 2MB | 循环覆盖,保留最近5份 |
| 崩溃日志 | 10个 | 1MB | 每次崩溃单独保存 |
| 网络日志 | 3个 | 500KB | 只保留最近3天的 |
| 用户操作日志 | 7个 | 1MB | 保留一周的操作记录 |
我曾经遇到过一个问题,日志轮转没做好,音箱用了一个月后存储空间满了,导致OTA升级失败。从那以后,我每次做固件都会仔细检查日志轮转策略。
4.4 三种方案的选型建议
说了这么多,到底该用哪种方案?我根据实际经验总结一下:
- 开发调试阶段:优先用ADB,方便快捷。遇到底层问题,上串口。
- 硬件测试阶段:串口必备,能看到完整的启动过程。
- 小批量试产:ADB+串口结合使用,同时开始搭建远程日志方案。
- 量产阶段:远程日志收集是标配,ADB和串口作为备用方案。
嗯,日志采集就讲到这里。说白了,ADB是日常主力,串口是最后防线,远程方案是量产保障。三种方案各有各的用处,关键是要根据实际情况灵活选用。下一章我们聊聊日志分析的具体方法,到时候会用到今天采集的这些日志数据。