用 jq 安全地解析与处理 JSON 日志
现在很多服务都把日志打成 JSON 格式,一行一条,字段齐全,看着规整。可真到了排查问题的时候,用眼睛一行行扫、拿 grep 硬搜字符串,既容易漏又容易误伤:搜 error 会把 "error_count": 0 也翻出来,搜状态码又分不清是请求还是响应里的。jq 就是为这种场景准备的工具:它把 JSON 当结构化数据来查,字段、类型、嵌套层级都清清楚楚。
一、先把日志「摆整齐」看
拿到一个 JSON 日志文件,先别急着过滤,用 jq 把它格式化输出,确认结构:
cat app.log | jq '.'
如果某一行不是合法 JSON,jq 会直接报出行号,这本身就是一种体检——很多「日志丢了」的假象,其实是写日志时混进了半行普通文本。只想看某几个字段也很简单:
cat app.log | jq '{time: .timestamp, level: .level, msg: .message}'
二、按字段过滤,比 grep 靠谱
排查故障时最常见的需求是「只看错误级别以上的日志」。用字段比较,一条命令搞定,而且不会被无关字段里的字符串误导:
cat app.log | jq 'select(.level == "error" or .level == "fatal")'
再比如只看耗时超过 1 秒的慢请求:
cat app.log | jq 'select(.duration_ms > 1000)'
因为比较的是字段的真实类型和值,duration_ms 是字符串还是数字一眼就能验证,不像 grep 那样只能对文本猜。
三、统计与汇总,顺手就做
定位问题往往还要回答「哪类错误最多」「每个接口平均耗时多少」。jq 内置了分组和聚合能力,不必再把数据导去别处:
# 按错误码统计出现次数
cat app.log | jq -s 'group_by(.status) | map({status: .[0].status, count: length})'
# 统计各级别日志条数
cat app.log | jq -s 'group_by(.level) | map({level: .[0].level, count: length})'
-s(slurp)会把多行 JSON 读成一个数组,再配合 group_by、map、length 就能做简单的报表。应急排查时,这种「一条命令出结论」的效率非常关键。
四、输出成表格,方便贴给同事
jq 的 @tsv 和 @csv 可以把查询结果转成制表符或逗号分隔文本,方便粘到表格或文档里沟通:
cat app.log | jq -r 'select(.level == "error") | [.timestamp, .service, .message] | @tsv'
-r 表示输出原始字符串、不带引号,配合 @tsv 复制出来就是整齐的三列。
五、两个安全习惯
第一,处理不可信的日志文件时,先小样验证再全量跑:head -n 100 app.log | jq ... 确认表达式没问题,再对整份文件执行,避免写错过滤条件还浑然不觉。第二,把复杂表达式写进脚本文件用 jq -f 调用,而不是在命令行里越拼越长,既能复用,也便于同事接手时看懂。
日志从「文本」变成「数据」之后,排查的思路也会跟着变:先按字段收窄范围,再做统计定位热点,最后抽取明细确认根因。jq 学起来不难,常用的就 select、group_by、map 这几个,值得放进每个运维的工具箱。
- 点赞
- 收藏
- 关注作者
评论(0)