用 jq 读 JSON 日志:去掉杂音的实用方法
服务返回 JSON 时,难的往往不是拿到数据,而是从嵌套对象、数组、时间戳和标识符里,找到真正说明问题的一条字段。jq 把程序写成过滤器:输入一个值,输出一个结果,不用手动翻文件改数据。
用过滤器思考,而不是用手工改
jq 1.8 手册说,过滤器可以组合:一个过滤器的输出可以用管道交给下一个,也能收集成数组。有的过滤器会产生多个结果,例如返回数组全部元素的过滤器,会对每个元素各运行一次后续过滤器。连 “hello” 或 42 这样的常量也是过滤器。
从最小的一步开始
最简单的过滤器是一个点 .,即恒等算子,原样复制输入。jq 默认会美化输出,所以只用 . 也能校验并格式化杂乱响应。
接着用 .status 取 status 键的值:键存在返回其值,不存在返回 null。缺失与显式 null 在排查时不一定等同,需要区分。
键不是简单标识符时,用方括号加引号,如 .[“request-id”];手册说点号写法只适用于简单标识符键。可选写法 .status? 在输入不是对象时不报错,日志各行结构不一致时能让查询继续。
在数组里一步步走,不要迷路
有意义的 JSON 往往不扁平,包含事件、条目或错误数组。.[] 会把数组元素逐个作为单独结果返回,而不是整个数组,随后管道可以逐个处理。
.events[] 得到每条事件,.events[] | .level 得到每条级别。方括号可收集结果:[.events[].id] 收集全部 id;对象简写 {time, level, message} 只保留这些字段。做日志摘要时,舍弃字段往往正是目的。
先筛选,再汇总
先筛选再汇总通常更好。select 在条件为真时原样输出输入,否则不输出,所以 .events[] | select(.level == “error”) 只保留错误;组合条件如 select(.level == “error” and .service == “checkout”)。
map 对数组每个值应用过滤器并返回数组,手册例子 [1, 2, 3] | map(select(. >= 2)) 得到 [2, 3]。sort_by(.time) 可按时间排序,group_by 把相同字段值的元素分到不同数组并按该字段排序,长串失败会变成少量分组。
让输出适合下一个工具
美化输出适合人阅读,但不一定适合交给下一个工具。-c 输出紧凑,每条结果一行;-r 是原始输出,字符串结果直接写出,不带 JSON 引号,适合取标识或消息。
–arg 传字符串,–argjson 传 JSON 编码值,例如 --arg level error 会让程序里的 $level 得到 “error”,逻辑不变,只换参数。手册还提醒,Unix Shell 里一般用单引号引用 jq 程序,因为许多对 jq 有特殊意义的字符也是 Shell 元字符。
给杂乱日志留一个冷静流程
查询出问题时先缩小:单独测第一个过滤器,再逐步加下一步。若某步没有输出,下一步就没有可处理的内容,整个结果可能悄悄消失,这常说明前面过滤器比预期更严格。
jq 的价值不在于了解你的系统,而在于提供一种精确描述所需 JSON 部分的语言;能把这部分说清楚,其余日志就可以退到一边,排查就变成读一份简短答案,而不是翻一份长文件。
- 点赞
- 收藏
- 关注作者
评论(0)