一、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参数会清空缓冲区,但不会影响后续日志的写入。我有个同事曾经在生产环境上敲了这个命令,结果被运维追着骂了半天——他以为只是清空自己终端的显示,实际上把设备上的日志全清了。

警告:生产环境慎用 adb logcat -c!清空缓冲区后,之前的日志就再也找不回来了。

1.2 日志缓冲区

Android的日志不是一股脑全写在一起的。它分了几个缓冲区,每个缓冲区管一类事情。我画了张图,你看一眼就明白了:

Android 日志缓冲区结构 应用层 (Application Layer) logd 守护进程 (日志写入入口) main 缓冲区 应用日志 (默认) system 缓冲区 系统组件日志 (framework) events 缓冲区 事件日志 (二进制格式) crash 缓冲区 崩溃日志 (异常信息) 每个缓冲区独立管理,可通过 -b 参数指定查看

这张图你看懂了吗?说白了,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级别,这不是给自己找麻烦吗?

注意:线上版本建议只保留Error和Warning级别的日志。Debug和Verbose日志会严重影响性能,还会暴露敏感信息。

1.4 日志标签规范

日志标签(Tag)是logcat里最常用的过滤手段。一个好的Tag,能让你在成千上万条日志里快速定位到目标。

Android官方推荐Tag长度不超过23个字符。为什么?因为logcat输出时,Tag字段固定宽度就是23。超了会被截断,看着难受。

我总结了几条规范,供你参考:

  • 类名做Tag:比如MainActivityNetworkManager。简单直接。
  • 模块前缀:比如Camera_OpenAudio_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