一、Android日志系统概述:logcat基础、日志缓冲区、日志级别、日志标签规范
各位好,我是老张。今天咱们聊聊Android日志系统。
做Android系统调试,说白了就是跟日志打交道。你想想看,系统跑着跑着出问题了,第一反应是什么?肯定是看日志啊。我入行那会儿,带我的师傅就说了一句话:「不会看log,就别做Android开发。」这话糙理不糙。
Android日志系统,核心就是logcat。它像是一个黑匣子,记录着系统里发生的每一件事。咱们今天就把这个黑匣子拆开看看。
1.1 logcat基础
logcat是Android提供的一个命令行工具。你连上设备,敲个adb logcat,日志就开始刷刷地往外蹦。我刚开始用的时候,觉得这玩意儿太简单了,不就是看日志嘛。后来才发现,这里面的门道多着呢。
先说说最基本的用法:
# 查看所有日志
adb logcat
# 清空缓冲区
adb logcat -c
# 将日志输出到文件
adb logcat -d > /tmp/log.txt
# 实时查看并过滤关键字
adb logcat | grep "Error"
嗯,这里要注意一点:-c参数会清空缓冲区,但不会影响后续日志的写入。我有个同事曾经在生产环境上敲了这个命令,结果被运维追着骂了半天——他以为只是清空自己终端的显示,实际上把设备上的日志全清了。
1.2 日志缓冲区
Android的日志不是一股脑全写在一起的。它分了几个缓冲区,每个缓冲区管一类事情。我画了张图,你看一眼就明白了:
这张图你看懂了吗?说白了,Android把日志分成了四个主要缓冲区:
| 缓冲区名称 | 用途 | 查看命令 |
|---|---|---|
| main | 应用层日志,大部分app的log都在这里 | adb logcat -b main |
| system | 系统服务、framework层的日志 | adb logcat -b system |
| events | 系统事件日志,比如Activity生命周期、ANR等 | adb logcat -b events |
| crash | 崩溃日志,专门存放异常信息 | adb logcat -b crash |
我个人习惯,调试系统问题时,会同时开三个窗口:一个看main,一个看system,一个看events。这样能快速定位问题出在哪一层。
adb logcat -b all 可以同时查看所有缓冲区。但信息量太大,建议配合grep使用。
1.3 日志级别
Android日志有六个级别,从低到高分别是:
- V (Verbose) — 啰嗦模式,啥都记。我一般不开,太吵了。
- D (Debug) — 调试信息,开发阶段用。
- I (Info) — 普通信息,比如「服务启动成功」这种。
- W (Warning) — 警告,可能有问题但没挂。
- E (Error) — 错误,出事了。
- F (Fatal) — 致命错误,系统要崩了。
每个级别对应一个字母,在logcat里一眼就能看出来。举个例子:
# 只显示Error及以上级别
adb logcat *:E
# 显示Warning及以上级别
adb logcat *:W
# 只看某个tag的Debug级别
adb logcat -s MyTag:D
我曾经遇到过一个坑:有个同事在线上版本里大量使用Log.v(),结果日志量暴增,把存储空间撑爆了。你想想看,生产环境用Verbose级别,这不是给自己找麻烦吗?
1.4 日志标签规范
日志标签(Tag)是logcat里最常用的过滤手段。一个好的Tag,能让你在成千上万条日志里快速定位到目标。
Android官方推荐Tag长度不超过23个字符。为什么?因为logcat输出时,Tag字段固定宽度就是23。超了会被截断,看着难受。
我总结了几条规范,供你参考:
- 类名做Tag:比如
MainActivity、NetworkManager。简单直接。 - 模块前缀:比如
Camera_Open、Audio_Play。方便按模块过滤。 - 统一风格:团队内部统一大小写和下划线规则。别一会儿驼峰一会儿下划线。
- 避免敏感信息:Tag里不要带用户名、密码、设备ID等。
代码里怎么用?看这个例子:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: 开始初始化");
// ... 业务逻辑 ...
Log.i(TAG, "onCreate: 初始化完成");
}
private void loadData() {
Log.d(TAG, "loadData: 开始加载数据");
try {
// ... 加载数据 ...
Log.i(TAG, "loadData: 数据加载成功");
} catch (Exception e) {
Log.e(TAG, "loadData: 数据加载失败", e);
}
}
}
嗯,这里有个细节:Log.e()的第三个参数可以传异常对象,这样日志里会带上完整的堆栈信息。调试时特别有用。
- Tag要短(≤23字符)、要清晰、要统一
- 不同级别用不同方法:Log.v()、Log.d()、Log.i()、Log.w()、Log.e()
- 异常信息一定要传Throwable对象
最后说一句:日志系统是调试的基石。你花半小时把日志规范搞好了,后面能省下三天排查问题的时间。这笔账,怎么算都划算。
公众号:蓝海资料掘金营,微信deep3321