💡 前言 高效优雅地查询日志是后端工程师的必修课。本篇文章详细介绍结构化日志查询工具的使用方法,并提供多种工具结合的实际案例分析。
我们假设当前目录下有多个日志文件,均为.log后缀,下面开始介绍日志查询命令。
🔍 读取日志的命令#
cat 命令#
cat 是 Linux/Unix 系统中最基础且常用的命令之一,全称为 “concatenate”(连接),主要用于读取、显示、合并文件内容,也可用于创建简单文件。以下是其详细用法:
- 读取单个日志文件:直接指定文件名,可查看该日志文件的全部内容。
cat test.log
- 读取多个指定日志文件:依次列出多个日志文件名,可一次性查看这些文件的内容(按输入顺序拼接展示)。
cat test1.log test2.log
- 读取当前目录下所有 .log 后缀的日志文件:使用通配符
*匹配所有以 .log 结尾的文件,文件内容将按“数字>大写字母>小写字母”的字符排序规则展示。
cat *.log
- 读取当前目录下以特定前缀开头的日志文件:通过“前缀+通配符”的组合,精准匹配目标文件(如下例匹配以 20250928 开头的所有日志文件)。
cat 20250928*.log
- 合并多个文件内容到新文件:使用重定向符号
>,将多个文件的内容合并后写入指定新文件(注意:>会覆盖目标文件的原有内容)。
cat test1.log test2.log > merged.log
- 追加文件内容到已有文件:若需保留目标文件原有内容,改用重定向符号
>>,将新文件内容追加到目标文件末尾。
cat file3.txt >> merged.txt # 将 file3.txt 的内容追加到 merged.txt 末尾
- 从标准输入(键盘)读取内容并保存到文件:不指定源文件时,
cat会默认从键盘读取输入,输入完成后按Ctrl+d结束并保存内容(适合快速创建短文本文件)。
cat > newfile.txt # 输入内容后按 Ctrl+d 保存
- 读取gz压缩文件:用
zcat命令可以直接读取gz压缩文件。
zcat test.log.gz
| 选项 | 功能说明 |
|---|---|
-n | 显示内容时,为每一行加上行号(包括空行) |
-b | 显示内容时,为非空行加上行号(忽略空行) |
-s | 压缩连续的空行为一个空行(去除多余空行) |
-E | 在每行末尾显示 $ 符号(方便区分行尾和空格) |
-T | 将制表符(Tab)显示为 ^I(方便查看隐藏的制表符) |
-v | 显示非打印字符(除换行和制表符外) |
如果想要实时监测日志更新,可以使用
tail -f命令查看如果单个日志文件过大,可以使用
less命令分页查看
cat是查询日志中最常用的命令,我们可以通过管道(|)将cat读取的内容传递给其他工具处理:
查看文件并搜索关键词(结合
grep):cat test.log | grep "ERROR" # 从 test.log 中筛选包含 ERROR 的行查看文件并排序(结合
sort):cat test.log | sort -n # 按数字排序文件内容
tail 命令#
- 查看 test.log 文件的末尾内容(默认显示最后10行)
tail test.log
- 实时跟踪当前目录下所有日志文件的更新 适用于持续写入的日志监控
tail -f *.log
- 增强版实时跟踪当日志文件被轮转切割(如按日期归档)时 自动跟随新的文件继续监控
tail -F *.log
less 命令#
打开文件:
less test.log # 分页查看 test.log也可结合管道接收其他命令的输出:
cat *.log | less # 分页查看所有 .log 文件的合并内容 cat test.log | grep "error" | less # 分页查看包含 error 的日志行核心操作快捷键:
- 翻页:
- 空格 /
f:向前翻一屏。 b:向后翻一屏。- 方向键 ↑/↓:逐行上下滚动。
- 空格 /
- 跳转:
g:跳转到文件开头。G:跳转到文件结尾。50g:跳转到第 50 行。
- 搜索:
/关键词:从当前位置向下搜索(如/ERROR搜索 ERROR)。?关键词:从当前位置向上搜索。- 按
n:跳转到下一个匹配结果。 - 按
N:跳转到上一个匹配结果。
- 其他:
q:退出查看。v:在当前位置用默认编辑器打开文件(方便修改)。Ctrl+f:向前滚动一屏(同空格)。Ctrl+b:向后滚动一屏(同b)。
- 翻页:
🎯 筛选日志的命令#
jq 及其常用函数#
基本取值#
.:获取整个JSON日志对象,用于格式化输出 示例:cat test.log | jq '.'(格式化打印日志).key:提取指定字段值(如日志中的timestamp、level) 示例:cat test.log | jq '.level'(提取所有日志级别).array[索引]:获取数组类型字段的指定元素(如日志中的tags[0]) 示例:cat test.log | jq '.tags[1]'(提取tags数组的第二个元素).key1.key2:嵌套取值(如日志中user.name) 示例:cat test.log | jq '.request.url'(提取请求URL)
条件过滤#
select(条件):筛选满足条件的日志条目 示例:cat test.log | jq '.[] | select(.level == "ERROR")'(筛选所有错误级别日志)
contains#
- 功能:判断数组/字符串是否包含指定元素/子串
- 用法:
select(.字段 | contains(目标值))示例1(字符串包含):筛选message含"timeout"的日志cat test.log | jq '.[] | select(.message | contains("timeout"))'
示例2(数组包含):筛选tags数组含"payment"的日志cat test.log | jq '.[] | select(.tags | contains(["payment"]))'
index#
功能:返回子串在字符串中的起始索引(不存在返回
null),用于精确位置判断用法:
select(.字段 | index(子串) != null)示例:筛选message中"error"出现在第5位及以后的日志cat test.log | jq '.[] | select(.message | index("error") >= 5)'
has#
功能:判断对象是否包含指定字段(日志中常用于检查是否存在某属性)
用法:
select(has("字段名"))
示例1:筛选包含stackTrace字段的错误日志cat test.log | jq '.[] | select(has("stackTrace") and .level == "ERROR")'
示例2:排除不含requestId的日志cat test.log | jq '.[] | select(has("requestId"))'
sort/uniq/group_by#
sort_by(字段):按指定字段排序日志
示例:按timestamp升序排列日志cat test.log | jq '.[] | sort_by(.timestamp)'unique:数组去重(常用于提取唯一值) 示例:提取所有不重复的userIdcat test.log | jq '.[] | .userId' | jq -s 'unique'group_by(字段)[]:按字段分组(统计前常用) 示例:按level分组统计日志cat test.log | jq '.[] | group_by(.level)'
length#
功能:返回数组的长度或者字符串长度
用法:
cat test.log | jq '.[] | length'获取日志数量cat test.log | jq '.message | length'获取日志message字符数
📊 统计分析日志的命令#
sort/uniq#
- 功能:搭配使用对数组进行排序和去重,常用于统计日志数据
- 用法:
cat test.log | jq '.level' | sort | uniq
wc#
- 功能:统计日志行数、单词数、字节数
- 用法:
cat test.log | wc -l获取日志行数
awk#
awk 是强大的文本处理工具,特别适合对日志进行字段提取、条件筛选和统计计算。它按行处理文本,并可基于分隔符将每行拆分为字段。
基本语法:
awk 'pattern {action}' file # pattern 为筛选条件,action 为处理动作按分隔符提取字段:假设日志按空格分隔,提取第1列和第3列
cat test.log | awk '{print $1, $3}' # $1表示第1列,$3表示第3列指定分隔符:使用
-F指定分隔符(如逗号、冒号等)cat test.log | awk -F ',' '{print $2}' # 按逗号分隔,提取第2列条件筛选:仅处理满足条件的行
cat test.log | awk '$3 > 100 {print $0}' # 筛选第3列数值大于100的行 cat test.log | awk '/ERROR/ {print $0}' # 筛选包含ERROR的行统计计数:使用内置变量
NR(行号)和NF(字段数)cat test.log | awk 'END {print NR}' # 统计总行数 cat test.log | awk '{sum+=$3} END {print sum}' # 累加第3列数值并输出总和格式化输出:使用
printf自定义输出格式cat test.log | awk '{printf "Level: %s, Message: %s\n", $1, $2}'多条件组合:结合逻辑运算符(&&、||、!)
cat test.log | awk '$1=="ERROR" && $3>50 {print $0}' # 第1列为ERROR且第3列大于50
常用内置变量:
| 变量 | 说明 |
|---|---|
$0 | 当前行的完整内容 |
$1, $2, $n | 当前行的第1、2、n列 |
NR | 当前处理的行号 |
NF | 当前行的字段总数 |
FS | 字段分隔符(默认为空格) |
OFS | 输出字段分隔符 |
💼 实战实例分析#
查询非 info 日志#
通过index排除部分无关日志
cat test.log | jq 'select(.level!="info" and (.msg | index("update") == null and index("config") == null)'
查询指定用户日志#
cat test.log | jq 'select(.uid == 123)'
cat test.log | jq 'select(.uid == 123 and (.message | contains("succ")))'
统计错误日志数#
cat test.log | jq 'select(.level=="error") | .request_id' | sort | uniq | wc -l
