ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

新版Android Studio Logcat筛选日志指南:从过滤器到正则实战

新版Android Studio Logcat筛选日志指南:从过滤器到正则实战 如果你最近把 Android Studio 升到新版本Koala 之后的版本基本都是第一次打开 Logcat 时大概率会愣一下——界面变了按钮少了看起来更像一个 IDE 内置的数据库查询工具。很多老开发都会问一个问题新版 Android Studio Logcat 筛选日志到底该怎么用这篇文章就以“新版 Android Studio Logcat 筛选日志”为核心把我这些时间实际使用新 Logcat 摸出来的门道整理一遍包括基础界面改动、过滤器是怎么工作的、高级搜索语法、连接真机抓崩溃日志、以及最常见的坑。内容偏向实操看完你直接照着操作就行不需要再去翻英文文档或者靠全网搜索拼拼凑凑。1. 新版 Logcat 为什么和旧版长得不一样1.1 从“一堆文本”到“一行一条结构化记录”旧版 Logcat 本质上是一个“滚动文本窗口”所有日志像流水一样从下往上刷你要筛选就输入关键字系统帮你做文本匹配日志多起来以后界面的响应速度会明显变差动不动就把 CPU 拉满。新版 Logcat 把底层数据存储方式换了日志不再是单纯的一段文本而是一条一条带结构化字段的记录。每一条日志都包含了时间、进程 ID、线程 ID、包名、优先级、标签、消息内容这些属性。这一步改动才是核心因为只有把这些字段拆开存储后面才能支持多维度组合筛选、崩溃堆栈折叠、历史日志回溯这些高级功能。你可以简单理解成旧版是拿记事本找文字新版是拿 Excel 表格做筛选。同样是在几十万条日志里找一条崩溃信息新版的速度和准确度都完全不一样。1.2 新版界面的四个区域先认清再上手新 Logcat 打开以后默认界面从上到下大概是这样的顶部是一排图标按钮包括清除日志、暂停滚动、过滤器管理、导入导出日志每一个按钮都有明确职责不再像旧版那样挤在一小块。下面是一个很明显的“筛选输入框”输入关键词或正则表达式后日志列表会实时变化。再往下是日志列表每一条日志默认以“高度折叠”的形式展示一行一条点开以后才会展示完整的线程信息、堆栈信息。右侧或底部还有一个可展开的“详情面板”专门用来展示选中日志的完整内容。如果你第一眼觉得不习惯不用着急这属于正常的适应期。真正需要花时间理解的不是按钮长什么样而是新版 Logcat 中筛选日志的逻辑已经完全变了它不再只是“搜索”而是“构建查询条件”。1.3 底层存储变了筛选不再是“文本找玩具”新版 Android Studio 对 Logcat 日志的存储设计有点像一个本地数据库日志不会因为界面滚动就丢失也不会因为暂时离开 Logcat 窗口就清空。只要你运行 App 时系统在捕捉日志那么这些日志就会持续写入本地缓存后面切回 Logcat 窗口依然可以查出刚才的历史记录。这也带来一个操作习惯的变化以前我调试一个问题先把 Logcat 打开再操作 App生怕日志刷过去了现在我可以先操作 App复现完问题再淡定切到 Logcat输入包名或启动进程把刚才这段日志捞出来慢慢分析。这个改动对反复复现闪退的同学特别友好。2. 四种过滤器搞清楚原理就能玩转筛选2.1 四种过滤器分别过滤什么新版 Logcat 的过滤器有四种主要类型很多人一开始只盯着输入框里的关键词搜索拍脑袋输几个单词却完全没意识到自己真正的需求要靠组合过滤才能完成。过滤器类型作用对象典型使用场景正则表达式日志的整个消息内容同时匹配多个关键字比如 Error包名当前进程所属的包只看自己的 App 日志过滤掉系统日志和别的应用日志进程 ID指定进程 ID多进程 App 或者只观察某个子进程日志级别日志优先级只保留警告、错误级别以上日志这里要特别提醒一下包名过滤和进程 ID 过滤在新版里面其实是挂钩的。你选择某个包名以后系统会自动列出与该包名相关的所有进程 ID反过来也一样。最常用的场景就是只选自己的包名然后配合错误级别去查崩溃日志。2.2 实际配置一个“应用过滤器”的步骤如果你像我一样同时开发多个项目或者设备上装了多个测试应用建议不要每次临时输入关键词去过滤而是创建几个“持久化过滤器”以后一键切换。具体操作步骤打开 Logcat 窗口点击顶部“过滤器”按钮通常是一个漏斗或者加号图标。在面板里选择“包名”输入你的应用包名例如com.example.myapp。“日志级别”默认选择 Verbose意思是不过滤级别想看全部如果定位错误可以先调成 Error。在“标签”位置填AndroidRuntime这在新版里可以保留为空但如果你很明确崩溃发生在运行时可以直接填这个标签。保存这个过滤器并给一个容易识别的名字比如“正式包崩溃日志”。保存之后以后每次点这个过滤器Logcat 窗口里就只显示这个包名下的日志和其他应用彻底隔离。这个操作非常基础但极其高频值得你花一分钟配好。2.3 一个容易忽略的参数日志级别与正则的组合日志级别一共有 Verbose、Debug、Info、Warn、Error、Assert 六种从低到高。默认情况下你看到的是 Verbose 级别也就是所有日志都展示出来。问题在于很多第三方 SDK 会疯狂打 Info 甚至 Debug 日志导致你自己的输出被夹在一大堆废日志里。我之前排查一个第三方 SDK 的启动问题满屏全是 SDK 自己打的 TAG眼睛都快找瞎了。后来我的做法是先选自己的包名再把日志级别调整为 Warn。这样一来不是关键信息的一律看不到只有警告和错误级别的日志会留下瞬间清爽很多。如果你还是想看自己代码里 Log.v 或者 Log.d 打的调试日志那就反过来级别选 Debug然后在输入框里填自己的 TAG 名称。组合拳永远比单一操作靠谱。3. 进阶搜索语法把日志“按需提纯”3.1 加不加引号结果差很多新版 Logcat 的搜索关键字默认对大小写不敏感这对大多数场景是好事但有个情况容易踩坑关键字包含空格的时候比如你想搜connect failed如果不加引号它会被拆成两个单词做“或”匹配也就是说包含connect或包含failed的日志全都会出来。想要精确匹配完整短语就需要给关键字加上英文双引号connect failed我实测下来这个细节很影响筛选效率。如果你搜NullPointerException单关键字问题不大但如果想找某个完整日志片段加引号能减少大量干扰项。3.2 正则表达式从入门到实用新版 Logcat 的搜索框支持正则表达式这是它比旧版强很多的地方。平时不会正则的同学不用担心这里只需要掌握几个最简单最实用的写法。比如我想同时抓Exception和Error两类日志直接输入Exception|Error注意如果你在新建过滤器的时候选了“正则表达式”模式那么输入规则就是正则如果没选那么默认还是普通关键字搜索。这两种模式的入口不一样需要留意。再比如我想看所有以MainActivity开头的标签可以写^MainActivity^符号表示“以什么开头”。这个在过滤 TAG 名称时特别好用因为很多自定义 TAG 明明属于同一个业务线却起了不同名字用正则就能一把梭。如果日志里有打印的 JSON 数据我只想找包含code:200的行正则里引号和冒号都是普通字符直接写就能匹配\code\:200或者为了稳妥也可以简化成code.{0,5}200这里的.{0,5}表示中间任意字符出现 0 到 5 次这招用来匹配格式不完全固定的日志非常实用。提示正则表达式写得多、范围广的时候日志列表刷新会变慢因为每个日志都要跑一遍匹配。如果设备性能一般建议配合包名和日志级别先缩小范围。3.3 折叠堆栈崩溃日志终于不再刷屏旧版 Logcat 遇到崩溃堆栈是几十行文本一次性刷出来你要复制、整理、肉眼找关键行。新版 Logcat 把堆栈做成了“可折叠结构”默认只显示第一行例如E/AndroidRuntime: FATAL EXCEPTION: main点一下这行日志左侧的展开箭头就能看到下面的完整堆栈Process: com.example.myapp, PID: 12345 java.lang.NullPointerException: Attempt to invoke virtual method ... at com.example.myapp.MainActivity.onCreate(MainActivity.java:25)这种折叠交互对排查崩溃非常友好。现在我做闪退分析的标准动作就是先过滤包名再选 Error 级别找到FATAL EXCEPTION行展开堆栈直接复制。整个过程比以前节省一半时间。3.4 用“保存过滤器”把常用正则固定下来正则这种东西每次手敲容易漏而且想到一半还要去查语法。我的建议是把常用的正则保存成命名过滤器一个收藏夹搞定。比如我长期保存了这么几个过滤器崩溃入口正则FATAL EXCEPTION|ANR in网络错误正则SocketTimeout|ConnectException|HTTP FAILED内存问题正则OutOfMemoryError|lowmemorykiller主线程卡顿正则Choreographer|Skipped frames每次遇到对应问题点一下即可思路不断档。这个习惯帮我省了很多重复操作强烈推荐你也建立一个自己的 Logcat 过滤器收藏夹。4. 真机场景抓崩溃、ANR、网络日志的实操方案4.1 如何从 Logcat 界面保存日志到文件新版 Logcat 自带导出功能并不一定非要敲命令。在 Logcat 窗口右上角找到一个“导出”图标点击后会弹出保存对话框可以选择将当前全部日志导出为.txt文件也可以选择导出为.log文件。我的建议是如果需要打包发给别人排查用.txt最方便如果是留档备份.log也没问题。重点是保存的时候要确认右侧的过滤条件是你想要的否则导出的内容很可能不完整。有一次我明明设置了包名过滤导出后文件里却有一堆系统日志后来发现是我在保存前不小心点击了顶部“清除过滤器”按钮日志列表变成了全量模式导出的自然是全量日志。所以导出前的检查步骤不能省至少要看一眼窗口标题上的过滤器名字对不对。4.2 直接使用 adb 命令抓取完整日志虽然新版 Logcat 的 UI 功能很强但我还是强烈建议每个 Android 开发者会几条 adb 日志命令因为真机上出现疑难问题、或者 App 闪退到根本来不及打开 AS 连接时命令行是最后一道防线。最常用的几条命令# 把当前缓存的全部日志输出并保存到文件 adb logcat -d full_log.txt # 只保留指定 TAG 且显示详细时间线程信息 adb logcat -s MyTag -v threadtime # 清空日志缓存用于复现前清零 adb logcat -c # 按进程 ID 过滤先通过包名拿 PID adb shell pidof com.example.myapp adb logcat --pid12345先解释一下这里每条命令的意图。-d表示 dump也就是把缓冲区里的日志一次性打印完并退出不阻塞如果你不加-d命令会一直挂在那里实时打日志适合实时观察场景。-c则是 clear清空日志缓存这个操作非常有用复现问题前先清一下后面拿到的日志干净又完整。--pid是只输出指定进程的日志适合多进程项目排查。无线调试的场景下如果你是使用新版 Android Studio 的“无线调试”功能连接手机这些 adb 命令也一样可以用不过需要先确保adb devices列表里能看到设备否则任何命令都是空转。4.3 抓 ANR 日志的完整思路以前我处理 ANR 问题第一反应是去/data/anr/traces.txt找堆栈但新版设备权限收紧以后非 root 状态下直接读这个目录很难。更靠谱的方法是通过adb bugreport抓取完整日志包然后从包里的 ANR 相关信息入手。adb bugreport bugreport.zip这个 zip 包里面内容很多包含系统当前所有调试信息。你不要一上来就硬翻而是直接检索ANR in关键字就能定位到发生 ANR 的包名和主线程堆栈。配合 Logcat 中过滤ANR in能看到 ANR 发生前后一段时间内的日志定位是否被主线程 I/O 卡住或者是否有死锁。说实话ANR 日志排查比崩溃日志麻烦不少因为触发场景千奇百怪。我自己的经验是先看 ANR 发生前 5 秒内的主线程日志重点关注正在执行的方法和是否有长时间持锁的迹象如果 logcat 里实在找不到线索再去看 bugreport 的完整堆栈。4.4 线上反馈问题封装一个“一键拉日志”脚本如果你经常需要帮运维或者测试同事拉日志可以写一个简单的 shell 脚本把清空日志、复现等待、抓取日志三步封装起来。#!/bin/bash # 简单日志抓取脚本用法./pull_log.sh com.example.myapp PACKAGE$1 adb logcat -c echo 日志缓存已清空开始复现问题... sleep 10 adb logcat -d --pid$(adb shell pidof $PACKAGE) -v threadtime crash_$(date %Y%m%d_%H%M%S).log echo 日志已保存脚本的思路很简单先清空缓存然后给测试或开发 10 秒时间在手机上复现问题最后按包名对应的 PID 把日志导出到本地。这样就算不懂 adb 命令的同事也能一键拿到干净的日志文件。5. 常见问题与排查技巧实录5.1 日志不刷新或者过滤器消失了怎么办新版 Android Studio 偶尔会有缓存不同步的问题具体表现是Logcat 窗口里日志停留在十几秒前不管你怎么操作 App界面都没变化。这种情况大概率不是没有日志而是 Logcat 视图暂停了。检查一下顶部工具栏的“暂停/恢复”按钮这个按钮很容易被误触。如果确认没暂停还不动就点一下“清除日志”按钮再重新操作 App通常就会恢复。还有一种更麻烦的情况你配置好的过滤器突然在面板里消失。这个多半是 Android Studio 的索引缓存出了问题。解决办法很直接关闭 Android Studio。删除项目目录下.idea文件夹中的logcat相关缓存文件。重新打开工程重新创建过滤器。如果你没有额外保存过滤器规则重建确实有点烦所以重要过滤器最好截图或写进团队文档里留存。5.2 System.out.println 不显示查日志全靠自己埋点很多教程还在教新手用System.out.println打印日志但这个思路在新版 Android Studio 里很容易出问题。官方推荐的日志方式是使用android.util.Log类Log.d(MyTag, debug message); Log.e(MyTag, error message);原因很简单Log类输出的日志会正确写入系统日志缓冲区并且带 TAG 和日志级别方便 Logcat 过滤而System.out在很多设备上会被重定向到独立的 stdout 缓冲区Logcat 界面里未必能看到或者混在一堆系统输出里根本找不到。如果你确实被迫要看System.out输出可以试试 adb 命令adb logcat -s System.out但这个 TAG 在部分国产 ROM 上真的不稳定强烈建议丢掉这个习惯老老实实用Log.d和Log.e对自己好一点。5.3 日志太长被截断怎么看完整内容很多日志库打印出来的超长消息在 Logcat 里会被系统截断成多段甚至直接丢失中间部分。这个问题在新版 Logcat 里依然存在因为系统日志缓冲区对单条消息的长度有限制。若你的 App 打印的日志特别长比如一大段 JSON 或者非常长的网络响应体建议在打印前自己分段处理或者直接写到本地文件。我实际项目里的做法是if (message.length() 3000) { File logFile new File(getExternalCacheDir(), long_log.txt); FileWriter writer new FileWriter(logFile, true); writer.append(message); writer.flush(); writer.close(); } else { Log.d(MyTag, message); }这虽然不是最优雅的方案但能保证日志不被系统截断而且文件路径固定后面直接在 AS 的 Device Explorer 里拉出来看就行。另外再提醒一点新版 Logcat 的缓冲区大小可以在 Android Studio 的设置里调整但不管怎么调日志量超级大的时候都会被丢弃。如果需要长期不间断记录还是要走文件输出这条路线。5.4 第三方库如 OkHttp日志不打印别怪 Logcat遇到网络请求排查时一个很常见的问题是明明代码里用了 OkHttp但 Logcat 里什么请求日志都没有。大多数情况下不是 Logcat 筛选的问题而是 OkHttp 默认没有开日志拦截器。项目 Gradle 里接入implementation com.squareup.okhttp3:logging-interceptor:4.12.0初始化时添加拦截器val loggingInterceptor HttpLoggingInterceptor().apply { level HttpLoggingInterceptor.Level.BODY } val client OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .build()配置好以后Logcat 里过滤关键字okhttp就能看到完整的请求 URL、请求头、响应体。顺便说一句日志级别选 BODY 时打印内容非常长建议只在 Debug 环境开Release 包一定记得关掉否则既敏感又影响性能。5.5 低版本 Android 设备上 Logcat 一直刷系统日志最后再说一个老设备的坑Android 8.0 以下的设备上Logcat经常会混入大量系统进程日志即使你选择了自己的包名还是有不相关的日志出现。这是因为低版本设备的日志缓冲区划分不如新版本清晰。这种情况的解决方案只有一个组合拳包名过滤继续开然后在搜索框里再加一层排除条件。比如想排除SurfaceFlinger和audio_hw这些高频系统日志正则写法可以参考(?!.*SurfaceFlinger)(?!.*audio_hw)^.*$这个正则的意思是不包含 SurfaceFlinger也不包含 audio_hw 的行才保留。它本质上利用了正则的负向前瞻。如果你的手机是 Android 9 以上这个问题会轻很多遇到的时候先别怀疑自己的筛选姿势大概率是设备系统本身导致的。写在最后的小心得从旧版 Logcat 迁移到新版刚开始那几天我确实挺抵触界面不一样按钮找不到连筛选的逻辑都要重新理解。但在实际项目里用了一两个星期以后我觉得新版这套思路是值得适应的尤其是结构化日志和可折叠堆栈让排查崩溃的效率提升非常明显。我个人体会最深的一点是新版 Logcat 的筛选并不是越复杂越好而是要理解每个过滤器的适用场景先缩小范围再精确定位。平时把常用过滤器保存好关键时刻真的能救命。如果你正在迁移新版 Android Studio或者已经被 Logcat 筛选问题搞得头大希望这篇文章能帮到你。后面我还会继续整理一些关于性能分析工具和模拟器调试的经验到时候再慢慢聊。
返回列表