4、日志分析实战:关键日志字段解读与grep/awk命令速查
日志分析,说白了就是故障排查的「第一现场」。
我做了这么多年运维,见过太多人一上来就重启系统,结果问题复现了还是抓瞎。其实,日志里已经把答案写好了,就看你会不会读。
这一节,我带你手把手拆解券商交易系统的日志。咱们不搞虚的,直接上干货。
4.1 交易系统日志长什么样?
先看一段真实的交易系统日志片段。这是我从某次生产事故中截取下来的,脱敏处理过:
2025-03-21 09:30:15.678 [trade-thread-12] ERROR c.t.s.trade.TradeHandler - [TXID:20250321093015001] 订单委托失败 | 账户:60012345 | 证券:600519.SH | 价格:168.50 | 数量:100 | 错误码:ERR_ACCT_BALANCE_INSUFFICIENT | 描述:可用资金不足,需冻结金额16850.00,实际可用余额12000.00
这段日志,信息量很大。我习惯把它拆成几个关键部分来看:
| 字段 | 示例值 | 解读 |
|---|---|---|
| 时间戳 | 2025-03-21 09:30:15.678 | 精确到毫秒,用于定位时间线 |
| 线程名 | [trade-thread-12] | 哪个线程在处理,方便追踪并发问题 |
| 日志级别 | ERROR | 严重程度,ERROR/WARN/INFO |
| 类名 | c.t.s.trade.TradeHandler | 哪个模块出的问题 |
| 交易ID | TXID:20250321093015001 | 全局唯一,串联整个交易链路 |
| 业务字段 | 账户、证券、价格、数量 | 交易要素,一眼看出是哪笔单子 |
| 错误码 | ERR_ACCT_BALANCE_INSUFFICIENT | 标准错误码,查手册用 |
| 描述信息 | 可用资金不足... | 人类可读的详细说明 |
核心要点:交易ID(TXID)是串联日志的「金线」。你排查问题时,第一件事就是找到这个ID,然后顺着它把上下游日志全部拉出来。
4.2 日志级别:别被INFO骗了
很多新手看到满屏的INFO日志,觉得一切正常。其实不然。
我遇到过最坑的一次:系统响应变慢,日志里全是INFO,没有一条ERROR。我差点就去查网络了。后来仔细一看,WARN级别的日志里写着「连接池等待超时,重试第3次」。嗯,这才是真凶。
常见的日志级别,我按优先级排了个序:
- FATAL — 系统要挂了,赶紧起来看看
- ERROR — 出错了,但系统还能撑一会儿
- WARN — 有隐患,比如重试、降级、限流
- INFO — 正常流程记录,别太当真
- DEBUG — 开发调试用,生产环境一般不开
我的习惯:排查问题时,先看ERROR和WARN。如果没找到,再考虑是不是日志级别没打对。我曾经有一次DEBUG了半小时,才发现是日志配置把ERROR级别给过滤掉了……
4.3 grep命令速查:从大海里捞针
日志文件动辄几个GB,你不可能一行一行看。grep就是你的「捞针神器」。
先来几个最常用的:
# 查找包含"ERROR"的行
grep "ERROR" app.log
# 查找某个交易ID的所有日志
grep "TXID:20250321093015001" app.log
# 忽略大小写查找
grep -i "timeout" app.log
# 显示匹配行的前后5行(上下文)
grep -C 5 "ERR_ACCT_BALANCE_INSUFFICIENT" app.log
# 只显示前10行(快速预览)
grep "ERROR" app.log | head -10
# 统计错误出现的次数
grep -c "ERROR" app.log
我个人最常用的是 -C 5。为什么?因为只看错误行往往不够,你得看看错误发生前后发生了什么。比如资金不足,前面是不是有一笔撤单没处理完?
注意:生产环境日志文件很大,grep时尽量加上时间范围过滤。比如先按日期切分,或者用 grep "2025-03-21 09:3[0-5]" 缩小范围。否则一个命令跑几分钟,你等得起,业务等不起。
4.4 awk命令速查:把日志变成表格
grep负责「找」,awk负责「拆」。日志里字段都是用分隔符隔开的,awk可以帮你把特定列提取出来。
看个例子。假设日志格式是固定的,用竖线 | 分隔:
# 提取第4列(账户号)和第6列(错误码)
awk -F '|' '{print $4, $6}' app.log
# 输出结果:
# 账户:60012345 错误码:ERR_ACCT_BALANCE_INSUFFICIENT
# 账户:60067890 错误码:ERR_STOCK_NOT_TRADABLE
再进阶一点,统计每种错误码出现的次数:
# 统计错误码分布
awk -F '|' '{print $6}' app.log | sort | uniq -c | sort -nr
# 输出结果:
# 152 错误码:ERR_ACCT_BALANCE_INSUFFICIENT
# 89 错误码:ERR_STOCK_NOT_TRADABLE
# 23 错误码:ERR_PRICE_LIMIT
你看,哪个错误最多,一目了然。我排查问题时,经常先用这个命令看看「大头」在哪。
避坑指南:我曾经遇到一个情况,awk提取出来的字段总是对不上。后来发现是日志里某个字段本身包含了竖线符号,导致列数错乱。解决办法是改用 awk -F ' \\| ',以「空格+竖线+空格」作为分隔符,这样更安全。
4.5 组合拳:grep + awk + sort
单个命令威力有限,组合起来才是真功夫。我常用的三板斧:
# 1. 先过滤出ERROR级别的日志
grep "ERROR" app.log > error.log
# 2. 提取交易ID和错误码
awk '{print $5, $9}' error.log
# 3. 按时间排序(如果日志时间戳在行首)
sort -k1,2 error.log
举个例子,我想查某个时间段内,某个账户的所有错误:
grep "2025-03-21 09:3[0-5]" app.log | grep "账户:60012345" | grep "ERROR"
这条命令干了三件事:先按时间过滤,再按账户过滤,最后按级别过滤。三层下来,结果通常只有几条,一眼就能定位问题。
4.6 实战案例:一次真实的资金不足排查
说个我亲身经历的事。某天开盘后,客服反馈有客户无法下单,提示「资金不足」。但客户说账户里明明有钱。
我当时的排查步骤:
- 先查日志:
grep "账户:60012345" app.log | grep "ERROR" - 发现错误码:
ERR_ACCT_BALANCE_INSUFFICIENT - 看上下文:
grep -C 10 "TXID:20250321093015001" app.log - 发现真相:原来客户有一笔未成交的买单,冻结了资金。但前端没展示这笔冻结,客户以为资金是自由的。
你看,日志不会骗人。它清清楚楚写着「可用资金不足,需冻结金额16850.00,实际可用余额12000.00」。问题不在系统,在展示逻辑。
总结一下:日志分析的核心就三步——找对字段、用对命令、看对上下文。grep负责筛选,awk负责提取,sort负责排序。这三样玩熟了,90%的日志问题你都能搞定。
4.7 本章知识体系图
下面这张图,帮你把本章的核心逻辑串起来:
嗯,这张图把整个流程串起来了。从日志结构开始,到级别判断,再到命令使用,最后落地到实战流程。你照着这个思路走,排查效率至少翻一倍。
公众号:蓝海资料掘金营,微信deep3321