跳过正文
高效日志查询分析工具实战指南
  1. 文章/

高效日志查询分析工具实战指南

💡 前言 高效优雅地查询日志是后端工程师的必修课。本篇文章详细介绍结构化日志查询工具的使用方法,并提供多种工具结合的实际案例分析。

我们假设当前目录下有多个日志文件,均为.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:数组去重(常用于提取唯一值) 示例:提取所有不重复的userId cat 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