别再无脑 cat 了!后端排查 GB 级生产日志的实战命令

1. 背景

刚接手复杂的线上业务,生产环境突然报出接口超时或进程崩溃,面对几 GB 甚至几十 GB 的滚动日志,你是丈二和尚摸不着头脑,还是熟练敲下组合命令瞬间定位问题?这种体现个人能力的关键时刻真的很重要~

在现代分布式系统架构中,后端服务的稳定性直接决定了业务的连续性。然而在生产环境下,日志文件往往具有体积巨大 (GB 级别)、多线程并发交织异常堆栈冗长 以及滚动轮转频繁等特点。

对于一名 Java 后端开发人员而言,掌握高效的 Linux 日志处理指令不仅是告别"加班排障"的利器,更是体现资深工程能力的试金石。本文将立足于真实的生产环境,系统性地总结查看日志的核心命令与实战组合连招

2.生产级的日志特征与排障陷阱

日志归档机制及其对分析的影响

由于生产环境日志产生速度极快,往往服务的日志配置会通过设置大小阈值或时间周期,将当前日志(如 app.log)重命名为历史归档(如 app.log.1.gz)并创建新的空文件继续写入 。这一机制决定了开发人员在跨越长时间跨度排查问题时,必须能够灵活使用处理压缩格式的指令,而非单纯依赖基础查看命令。

日志查看命令的性能平衡与安全选择

在生产环境中,严禁直接使用 vivim 打开巨大的日志文件,因为这些编辑器会尝试将文件全部加载进内存,导致严重的 IO 阻塞甚至触发内存溢出。开发人员应根据查看深度和实时性要求,在 catlesstail 之间做出明智选择

分布式链路追踪与跨服务日志关联

在微服务时代,单机的日志分析往往只能看到局部。Java 后端开发通常依赖 MDC(Mapped Diagnostic Context)技术将 TraceId 注入日志布局中。关于分布式链路追踪的知识点,请看之前我们总结的:Spring Boot项目如何实现分布式日志链路追踪

当用户反馈请求报错时,获取该请求唯一的 TraceId 是排查的第一步。在多台服务器构成的集群中,虽然可以通过集中式日志平台(如 ELK)查看,但有时直接在服务器上通过命令行实时分析更为即时 。

  • 跨文件聚合grep -h "trace-123456" *.log | sort。 使用 -h 隐藏文件名,将散落在业务日志、中间件日志、审计日志中的相同 TraceId 记录提取出来,并按时间戳排序,还原完整的请求链路 。
  • 链路完整性校验 :通过 grep 配合 findxargs 可以快速在整个日志目录(包含子目录)中定位链路的缺失点: find /var/log/myapp -name "*.log" | xargs grep "trace-123456"

3.核心实战命令精讲

3.1 grep:排障出场率 99% 的绝对主力

grep (Global Regular Expression Print)是查看日志实战中使用最多的命令,没有之一。它是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。核心配置项选项如下:

核心选项 动作说明 生产实战场景
-A n / -B n / -C n 打印匹配行的 后/前/前后 n 必用! 抓取完整的 Java Exception 异常堆栈
-v 反向匹配(排除) 过滤掉心跳检测(如 grep -v "healthCheck"
-i 忽略大小写 搜索 exception 或 Exception 均可命中
-E 支持扩展正则表达式 grep -E "1-9+"
-h 隐藏文件名 多文件聚合查找时,让输出更纯粹

展示命令示例之前先看看日志文件结构:

lua 复制代码
plasticene-admin % ls
app-debug-2026-03-25.0.log  app-error.log     app-interface.log
app-debug.log     app-info.log      app-warn-2026-03-25.0.log
app-error-2026-03-25.0.log  app-interface-2026-03-25.0.log  app-warn.log

常见日志查找是根据请求的traceId或者代码里面info输出的关键字查找的,如常用的根据traceId查找

bash 复制代码
grep '2037009686800355328' *.log

结果如下所示:

可以看到默认显示了具体的文件名和对应查找到的日志信息,但是我们一般是想按照请求链路时间顺序查看日志,而不是根据文件分开展示,不方便根据实际调用链路追踪,命令如下:

bash 复制代码
grep -h '2037009686800355328' *.log | sort

注意:默认情况下sort 会将查找到整行作为一个字符串 进行比较,按照字符的 ASCII/Unicode 编码顺序排序,所以加上了选项-h:不显示文件名,这样每行以时间开头。

结果如下所示:

可以看到日志根据时间顺序展示了,碍于篇幅问题,下面我只会展示示例命令,不再展示结果输出了~

如果你的日志格式时间不是放到最前面,如:

sql 复制代码
app-debug.log:[2036988356092674048] [DEBUG] [2026-03-26 10:07:25.026] [http-nio-9000-exec-1@72976]  com.plasticene.admin.dao.UserDAO.selectList_mpCount debug : ==>  Preparing: SELECT COUNT(*) AS total FROM user

那就得调整下sort命令的使用:

bash 复制代码
grep '2036988356092674048' *.log | sort -t '[' -k4,4

说明

  • -t '[':使用 [ 作为字段分隔符
  • -k4,4:按第4个字段(时间戳字段)排序

这样可以将所有文件中的日志按时间顺序排列

不过强烈建议日志格式第一列设置成时间,这样简洁明了,也方便查询

在生产环境中,grep真正的威力在于对上下文(Context)的捕捉。Java 的异常堆栈通常跨越数十行,如果只搜索 "Exception" 关键字而不带上下文,会丢失最有价值的栈顶调用信息。使用选项 -A (After)、-B (Before) 和 -C (Context) 参数来输出匹配显示行的上下行内容信息

比如说请求某个接口报错了,根据traceId去查看error日志:

lua 复制代码
grep '2036706972224598017' app-error.log

结果只是展示一行,根本看不到异常信息:

css 复制代码
[2036706972224598017] [ERROR] [2026-03-25 15:29:17.797] [http-nio-9000-exec-1@65245]  com.plasticene.boot.web.core.global.GlobalExceptionHandler exceptionHandler : 【系统异常】

正确的姿势是

lua 复制代码
# 抓取报错及其后面的 50 行堆栈信息
grep -A50 '2036706972224598017' app-error.log

再比如有些调用三方接口的请求参数和响应结果在info中进行换行格式化输出,这时候也需要查看上下文关联相关信息:

perl 复制代码
grep -C5 '2036706972224598017' app-info.log | grep 'url地址'

使用正则表达式匹配:

csharp 复制代码
# 1. 查看所有超过1000ms的请求
grep -E '耗时[[0-9]{4,}]毫秒' interface.log
# 2. 统计数量
grep -E '耗时[[0-9]{4,}]毫秒' interface.log | wc -l
# 3. 统计数量
grep -cE '耗时[[0-9]{4,}]毫秒' interface.log

最后谈谈和cat命令的关联使用,如cat app-info.log | grep '2036706972224598017'grep '2036706972224598017' app-info.log效果是一样的,但cat 会启动一个额外的进程并通过管道传递数据,这在处理 GB 级别的生产日志时会产生不必要的 CPU 和 I/O 开销。直接运行 grep "pattern" filename 效率更高,大日志文件完全不建议使用cat,cat更适合查看小型配置文件或系统状态,直接屏幕展示。

3.2 tail

在屏幕上显示指定文件的末尾若干行,不指定行数时默认显示末尾10行。命令选项如下:

css 复制代码
-c, --bytes=NUM                 输出文件尾部的NUM(NUM为整数)个字节内容。
-f, --follow[={name|descript}]  显示文件最新追加的内容。"name"表示以文件名的方式监视文件的变化。
-F                              与 "--follow=name --retry" 功能相同。
-n, --line=NUM                  输出文件的尾部NUM(NUM位数字)行内容。
--pid=<进程号>                  与"-f"选项连用,当指定的进程号的进程终止后,自动退出tail命令。
-q, --quiet, --silent           当有多个文件参数时,不输出各个文件名。
--retry                         即是在tail命令启动时,文件不可访问或者文件稍后变得不可访问,都始终尝试打开文件。使用此选项时需要与选项"--follow=name"连用。
-s, --sleep-interal=<秒数>      与"-f"选项连用,指定监视文件变化时间隔的秒数。
-v, --verbose                   当有多个文件参数时,总是输出各个文件名。
--help                          显示指令的帮助信息。
--version                       显示指令的版本信息。

tail 命令在开发联调和实时监控中几乎是不可或缺的。通过 -f (follow) 参数,开发人员可以持续观察文件的末尾追加内容 。

在真实的生产场景中,由于存在日志轮转,建议使用 tail -F 而非 tail -f-F 选项会自动检测文件名的变化。当 app.log 达到阈值被重命名为 app.log.1 时,tail -f 会停止工作,而 tail -F 则会尝试重新打开名为 app.log 的新文件,从而保证监控的连续性 。此外,配合 -n 参数可以指定初始查看的行数,如 tail -n 100 -f app.log,这在重启服务后检查初始化日志是否正常时非常有用

bash 复制代码
tail file #(显示文件file的最后10行)
tail -n +20 file #(显示文件file的内容,从第20行至文件末尾)
tail -c 10 file #(显示文件file的最后10个字节)
​
tail -25 app-info.log # 显示 mail.log 最后的 25 行
tail -f app-info.log # 等同于--follow=descriptor,根据文件描述符进行追踪,当文件改名或被删除,追踪停止
tail -F app=info.log # 等同于--follow=name --retry,根据文件名进行追踪,并保持重试,即该文件被删除或改名后,如果再次创建相同的文件名,会继续追踪
​

3.3 sed

sed(Stream Editor,流编辑器)是排查问题查看日志的"瑞士军刀"。它最大的优势在于非交互式 处理:它不需要像 vim 那样将整个文件加载到内存中,而是逐行读取并处理。这使得它在处理 GB 级别的生产日志时既安全又高效。

有时候我们没办法得到准确traceId或者关键字信息通过grep去快速过滤日志,只知道一个大概的时间范围,这时候sed就能排上用场了:

c 复制代码
sed -n '/2026-03-26 10:15/, /2026-03-26 10:20/p' app-info.log 

经验贴士 :模式匹配是"精确匹配"。如果 10:20:00 这一秒刚好没日志,sed 可能会一直打印到文件末尾。建议匹配到分钟即可

sed的功能挺强大的,关于sed的详细信息请看:wangchujiang.com/linux-comma...

3.4 awk

awk 实际上是一门完整的文本处理编程语言。对于 Java 开发来说,它最强大的地方在于能把"非结构化"的日志看作"结构化"的表格,非常适合处理 Nginx 访问日志、Tomcat 日志或进行 JVM 性能数据的二次统计

awk 按行读取文件,默认以空格或制表符将每行切分成多个列(Fields)。

  • $0:表示当前整行内容。
  • $1, $2...$n:表示第一列、第二列,以此类推。
  • $NF:表示最后一列(Number of Fields,在不知道列数时极好用)。
  • NR:当前处理的是第几行(Number of Records)。
  • FS :输入字段分隔符,默认为空格,可通过 -F 修改

假如日志的最后一列打印耗时

arduino 复制代码
192.168.1.10 - - [26/Mar/2026:00:01:01 +0800] "GET /api/user/info HTTP/1.1" 200 512 1.205

那么统计超过1s以上的请求命令如下:

dart 复制代码
# 打印时间、请求路径和具体的耗时数值
awk '$NF > 1.0 {print $1, $7, $NF}' access.log

awk功能也很强大,详细信息请看:wangchujiang.com/linux-comma...

3.5 less

less 是 一个强大且安全的日志查看工具。与 more 不同,less 采用了延迟加载技术,仅在用户翻页时读取文件内容,这使其在处理数 GB 规模的文件时依然能保持瞬间响应

在生产分析中,less 的交互快捷键是提高排查效率的关键。通过 /pattern 可以进行向下搜索,而 ?pattern 则支持向上回溯搜索 。在搜索结果中,按下 n(next)跳转到下一个匹配项,N 则回到上一个。如果需要实时观察日志并具备随时停下来检索的能力,执行 less +F <filename> 是最佳选择。这种模式下,less 的行为类似于 tail -f,但用户只要按下 Ctrl+C 就能立刻切换回浏览模式,进行前后翻页或关键字搜索,分析完毕后再按 F 即可恢复实时监控 。

Less 交互命令 动作说明 实用技巧
Space / f 向下翻一页 快速扫描最近的大段输出 。
b 向上翻一页 寻找报错堆栈的起始位置 。
G 跳转到文件末尾 快速到达最新生成的日志记录 。
g 跳转到文件起始 检查服务启动阶段的初始配置加载 。
&pattern 仅显示匹配行 类似于实时过滤,隐藏所有不相关的噪音日志 。
-N 显示行号 配合代码库定位具体的报错行 。

比如说上面根据sed查看指定时间区间的日志,如果日志量过大会刷屏,这时候就可以通过less进行分屏翻页:

c 复制代码
sed -n '/2026-03-26 10:15/, /2026-03-26 10:20/p' app-info.log | less

3.6 查看压缩归档日志

生产环境中,为了防止磁盘爆满,历史日志通常会被压缩为 .gz 格式。Linux 提供了专门用于操作压缩文本的指令集。这些指令会在后台使用流式解压并直接将数据传给分析引擎,避免了生成中间文件的开销 。

压缩指令 对应原始指令 应用场景
zgrep grep 在多天的归档压缩包中查找一个特定的 TraceID 。
zless less 查看一周前的历史日志归档,寻找配置更改的痕迹 。
zcat cat 将压缩日志流导向 awksed 进行离线数据分析 。
zmore more 快速翻阅归档文件内容 。

4. 实战组合拳

真正体现排障效率的,是把基础命令串联起来形成数据流(Pipeline)。以下是几个我在做复杂业务系统(如定时任务调度、长链路工作流)时常用的高阶组合拳。

连招一:快速统计指定时间段内的特定业务执行频次

场景:排查"逾期任务自动撤销"定时任务在特定时间段内究竟触发了多少条记录。

bash 复制代码
sed -n '/15:00/,/15:30/p' app-info.log | grep "逾期任务自动撤销" | wc -l

连招二:统计出现次数最多的 Top 10 异常(巡检必备)

场景:系统巡检时,想知道当前 error 日志里哪种异常最为泛滥。

bash 复制代码
# 提取带有 Exception 的行,用 awk 打印最后一列(通常是异常类名),去重统计并倒序排列,取前 10
grep "Exception" app-error.log | awk '{print $NF}' | sort | uniq -c | sort -nr | head -n 10

连招三:捕捉慢请求并提取耗时接口

场景 :Nginx 或业务网关日志中,抓取耗时大于 1000ms 的请求路径。 (假设日志格式:[时间] "GET /api/user" 200 1.205,耗时在最后一列)

bash 复制代码
awk '$NF > 1.0 {print $7}' access.log | sort | uniq -c | sort -nr | head -n 10

连招四:跨多文件、多目录的海量捞针

场景:一个请求跨越了多个微服务模块,日志被分散在不同的子目录下,你想强行找出包含该 TraceId 的所有日志文件并定位。

lua 复制代码
# 配合 find 和 xargs,在整个 /var/log/ 目录下地毯式搜索
find /var/log/myapp -name "*.log" | xargs grep "2036706972224598017"

5. 总结

在云原生和集中式日志(ELK / SkyWalking)大行其道的今天,熟练掌握 Linux 原生日志命令似乎显得有些"复古"。但作为一名资深研发,总会遇到集中日志平台延迟、崩溃,或者需要登录跳板机直连隔离环境排查底座问题的时刻。

这些命令就像是开发者手中的瑞士军刀,平时藏于终端,关键时刻拔剑出鞘,一针见血。

相关推荐
剑神一笑6 小时前
Linux pgrep 命令详解:按名称查找进程 PID 的高效方法
linux·运维·chrome
剑神一笑7 小时前
Linux killall 命令详解:按进程名批量终止进程的原理与实践
linux·运维·chrome
红尘散仙7 小时前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
卷毛的技术笔记8 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
会编程的土豆9 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
喵个咪9 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
basketball6169 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
qq_2518364579 小时前
SpringBoot+Vue 共享电池柜管理系统 完整实现 前后端分离项目实战 完整代码
vue.js·spring boot·后端
zhangxingchao10 小时前
AI 大模型核心六:量化、Workflow 与 Agent、多轮 RAG
前端·人工智能·后端
IT_陈寒11 小时前
Vite打包时遇到的坑,原来问题出在这里
前端·人工智能·后端