3、日志过滤与搜索:使用grep进行关键字过滤、多条件组合过滤、正则表达式在日志分析中的应用、时间范围过滤

日志文件动不动就几百兆,甚至几个G。你不可能一行一行去看。这时候,grep就是你的瑞士军刀。我个人习惯,打开终端第一件事就是敲grep,它帮我节省了至少80%的排查时间。

3.1 基础关键字过滤:从大海捞针到精准定位

最简单的用法,就是直接搜一个词。比如你想看所有包含“crash”的日志:

adb logcat | grep "crash"

嗯,这里要注意。如果你在Windows的CMD里跑,记得用双引号。Linux或Mac下单引号双引号都行,但为了统一,我建议都用双引号。

我在项目中遇到过一个问题:搜“error”出来一大堆,但很多是第三方库的冗余信息。怎么办?加个-i参数忽略大小写,或者用-w做整词匹配:

adb logcat | grep -iw "error"

这样就不会把“ErrorHandler”这种也匹配出来了。说白了,-w就是告诉grep:我只想要完整的单词“error”,别给我拆开。

小技巧: 如果你只想看某个进程的日志,比如system_server,可以这样:adb logcat -s system_server | grep "crash"。先按进程过滤,再按关键字过滤,效率翻倍。

3.2 多条件组合过滤:与、或、非的灵活运用

实际工作中,很少只搜一个词。比如我想看“anr”相关的日志,但又不想看“InputDispatcher”的ANR(因为那通常是输入事件超时,不是真正的应用ANR)。这时候就需要组合过滤。

与(AND)操作: 用管道串联多个grep

adb logcat | grep "anr" | grep -v "InputDispatcher"

-v就是取反,排除掉包含“InputDispatcher”的行。我曾经排查一个系统ANR问题,就是靠这个组合过滤,把几百条日志缩减到十几条,最终定位到是某个服务持锁导致。

或(OR)操作:-E开启扩展正则,或者用\|

adb logcat | grep -E "anr|crash|watchdog"

这样就能同时匹配ANR、crash、watchdog三种关键字。我个人习惯用-E,因为可读性更好。

非(NOT)操作: 就是上面说的-v。可以叠加使用:

adb logcat | grep "error" | grep -v "vendor" | grep -v "debug"

你想想看,这样一层层过滤下去,最终留下的就是真正需要关注的核心日志。

核心思路: 先宽后窄。先用一个宽泛的关键字把相关日志捞出来,再用排除法去掉噪音。不要一开始就想着精确匹配,那样容易漏掉线索。

3.3 正则表达式在日志分析中的应用

正则表达式,说白了就是更高级的搜索模式。grep默认支持基础正则,加上-E后支持扩展正则,功能更强。

常见场景1:匹配行首或行尾

日志的每一行通常以日期或优先级开头。比如我想找所有以“E/”开头的行(Error级别):

adb logcat | grep "^E/"

^表示行首。同理,$表示行尾。比如你想找以句号结尾的行,虽然不常用,但知道总没坏处。

常见场景2:匹配任意字符

点号.匹配任意单个字符。比如我想找“pid 1234”或“pid 5678”这种模式:

adb logcat | grep -E "pid [0-9]+"

[0-9]+表示匹配一个或多个数字。我在项目中遇到过需要提取所有进程ID的场景,用这个正则配合-o参数(只输出匹配部分),就能快速拿到所有PID列表。

常见场景3:匹配时间戳

Android日志的时间戳格式通常是“01-01 12:00:00.123”。如果你想找某个特定秒内的日志:

adb logcat | grep -E "01-01 12:0[0-5]:"

这表示匹配12:00到12:05之间的所有日志。嗯,这里要注意,正则写得太复杂容易出错,我建议先写个简单的测试一下,确认没问题再正式用。

避坑指南: 我曾经写了一个复杂的正则,结果grep跑了几分钟没反应。后来发现是正则回溯导致性能爆炸。记住:日志分析追求的是快,正则能简单就简单。如果实在复杂,可以考虑用awk或sed。

3.4 时间范围过滤:只关注关键时间窗口

很多时候,问题只发生在某个时间点前后。比如用户反馈“下午3点手机重启了”,你不需要看全天的日志。

方法1:用grep配合时间字符串

如果日志文件已经保存到本地,可以直接用grep匹配时间:

grep "15:00" bugreport.txt

但这只能精确到分钟。如果想看15:00到15:05之间的日志,可以用正则:

grep -E "15:0[0-5]:" bugreport.txt

方法2:用sed截取时间范围

我个人更推荐用sed,因为它可以按行号或模式截取。比如我想看15:00:00到15:05:00之间的日志:

sed -n '/15:00:00/,/15:05:00/p' bugreport.txt

这个命令的意思是:从匹配“15:00:00”的行开始打印,直到匹配“15:05:00”的行结束。注意,如果日志里没有精确的“15:05:00”,它会一直打印到文件末尾。所以最好选一个肯定存在的日志行作为结束标记。

方法3:实时过滤logcat的时间

如果你在实时抓取logcat,可以用-T参数指定起始时间:

adb logcat -T "01-01 15:00:00.000"

这样只会显示该时间点之后的日志。我经常在复现问题前先执行这个命令,等用户复现完,日志就已经被精准截取了。

实战经验: 有一次我排查一个偶现的冻屏问题,日志文件有2GB。我先用grep找到异常发生的时间点,然后用sed截取前后各30秒的日志,最终在不到1000行里找到了关键线索——一个死锁的堆栈。如果没有时间范围过滤,我可能要看几天。

3.5 综合实战:一个完整的日志过滤流程

假设你要排查一个“应用闪退”的问题。用户说“大概在下午2点半左右”。你的操作流程应该是:

  1. 先按时间截取: sed -n '/14:29:00/,/14:31:00/p' bugreport.txt > window.txt
  2. 再按关键字过滤: grep -E "crash|fatal|exception|ANR" window.txt > crash_log.txt
  3. 排除干扰项: grep -v "vendor" crash_log.txt > final_log.txt
  4. 查看上下文: grep -C 5 "com.example.app" final_log.txt (显示匹配行前后各5行)

这样下来,原本几万行的日志,最终可能只剩下几十行。你想想看,是不是效率高了很多?

总结一句话: grep是日志分析的基石。掌握好关键字过滤、组合过滤、正则和时间截取这四板斧,你就能在日志的海洋里精准定位问题。别怕记不住命令,多用几次就熟练了。我刚开始也是边查边用,慢慢就形成了肌肉记忆。