3、日志分析工具:grep、awk、sed在日志分析中的应用、日志分析脚本编写入门

日志分析,说白了就是在一堆看似杂乱无章的文本里,找到你想要的线索。我刚开始接触系统运维那会儿,面对动辄几个G的日志文件,真是头皮发麻。后来慢慢摸清了门道,发现只要用好三个工具——grepawksed,再配合一点脚本思维,大部分问题都能迎刃而解。

嗯,咱们今天就聊聊这三个老伙计,以及怎么把它们串起来写点实用的分析脚本。

3.1 grep:最快的文本搜索器

grep 是我用得最频繁的工具,没有之一。它的核心能力就一个字:。从海量日志里捞出你关心的那几行,是它的看家本领。

我个人习惯,排查问题时第一反应就是 grep。比如系统报了个 OutOfMemoryError,我直接敲:

grep "OutOfMemoryError" /var/log/app.log

这就把包含错误关键字的行全拎出来了。但光这样还不够,你想想看,错误发生前后往往有上下文信息。这时候 -C 参数就派上用场了:

grep -C 5 "OutOfMemoryError" /var/log/app.log

这个命令会把匹配行以及它前后各5行都打印出来。我在项目中遇到过好几次,光看错误行根本看不出原因,但看了上下文才发现是某个连接池配置出了问题。

小技巧: 如果日志文件特别大,比如超过1GB,建议先用 grep -c 统计一下匹配行数,心里有个数再决定要不要全量输出。我曾经直接对一个5GB的日志文件执行 grep,结果终端卡了半分钟……嗯,从那以后我就学乖了。

另外,grep 支持正则表达式,这是它的杀手锏。比如你想找所有IP地址:

grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' /var/log/access.log

-E 启用扩展正则,-o 只输出匹配的部分。这样你得到的就是一列干净的IP地址,方便后续处理。

3.2 awk:列处理与格式化输出

grep 擅长找行,但找到行之后,往往需要提取其中的某些字段。这时候 awk 就登场了。它默认以空格或制表符分割每一行,然后通过 $1$2 来引用第1列、第2列。

举个例子,Apache 的访问日志格式通常是这样的:

192.168.1.1 - - [10/Oct/2023:13:55:36 +0000] "GET /index.html HTTP/1.1" 200 2326

我想提取出所有返回状态码为500的请求的IP地址和请求路径,可以这么写:

awk '$9 == 500 {print $1, $7}' /var/log/apache2/access.log

这里 $9 是状态码(第9列),$1 是IP,$7 是请求路径。一行命令,就把关键信息筛出来了。

我记得有一次线上服务间歇性超时,排查了半天没头绪。后来我用 awk 统计了每个IP的请求次数:

awk '{count[$1]++} END {for (ip in count) print ip, count[ip]}' /var/log/nginx/access.log | sort -k2 -rn | head -10

结果发现有一个IP的请求量是其他IP的几十倍,明显是爬虫在捣乱。嗯,找到元凶后直接封掉,问题就解决了。

核心思路: awk 的威力在于它的关联数组和内置变量。你可以把它理解成一个微型编程语言,能完成条件判断、循环、统计等复杂操作。

3.3 sed:流式文本编辑器

sed 的名字叫流编辑器,说白了就是批量替换和修改文本。它不会直接修改原文件(除非你用 -i 参数),而是把处理后的结果输出到标准输出。

最常见的用法是替换字符串。比如日志里有个旧的IP地址 10.0.0.1,现在要改成 10.0.0.2

sed 's/10\.0\.0\.1/10.0.0.2/g' old.log > new.log

注意,正则表达式里的点号 . 需要转义成 \.,否则它会匹配任意字符。这个坑我踩过,有一次替换IP地址,结果把 10.0.0.11 也误改了……

除了替换,sed 还能删除特定行。比如你想去掉日志里所有以 # 开头的注释行:

sed '/^#/d' config.log

或者只打印第10到第20行:

sed -n '10,20p' /var/log/syslog

-n 参数表示不自动打印,只有明确用 p 命令的行才会输出。这个组合在查看日志中间部分时非常实用。

注意: 使用 sed -i 直接修改原文件时,建议先备份。我曾经在线上环境执行 sed -i 's/old/new/g' /etc/nginx/nginx.conf,结果正则写错了,把配置文件改坏了……还好有备份,不然就等着挨骂吧。

3.4 日志分析脚本编写入门

单个工具能解决简单问题,但实际工作中,我们往往需要组合使用。写一个简单的 Shell 脚本,把 grepawksed 串起来,就能实现自动化分析。

下面这个脚本,是我以前处理 Nginx 访问日志时写的。它的功能是:统计过去一小时内,返回 5xx 错误的 Top 10 URL。

#!/bin/bash
# 文件名:analyze_5xx.sh
# 用途:统计过去1小时内返回5xx错误的Top10 URL

LOG_FILE="/var/log/nginx/access.log"
CURRENT_HOUR=$(date +"%d/%b/%Y:%H")
TEMP_FILE="/tmp/5xx_errors.txt"

# 第一步:用grep筛选出当前小时的5xx错误行
grep "$CURRENT_HOUR" "$LOG_FILE" | grep -E 'HTTP/1\.[01]" 5[0-9]{2}' > "$TEMP_FILE"

# 第二步:用awk提取URL并统计出现次数
awk '{
    # 提取请求路径(第7列)
    url = $7
    # 用关联数组计数
    count[url]++
}
END {
    # 输出统计结果
    for (u in count) {
        print count[u], u
    }
}' "$TEMP_FILE" | sort -k1 -rn | head -10

# 清理临时文件
rm -f "$TEMP_FILE"

这个脚本的思路很清晰:

  1. 筛选:用 grep 先按时间范围过滤,再按状态码过滤。
  2. 提取与统计:用 awk 提取URL字段,并用关联数组计数。
  3. 排序与输出:用 sort 按次数降序排列,取前10条。

我在项目中遇到过类似场景,当时线上某个接口突然大量报500错误,我手动跑了一遍这个脚本,发现是某个新上线的API路径被频繁调用,而那个接口存在内存泄漏。嗯,找到问题后,回滚代码就解决了。

进阶建议: 脚本写好后,可以把它加到 cron 定时任务里,每小时自动执行一次,并把结果发送到邮箱或写入监控系统。这样你就不用每天手动跑脚本了。

最后,我想说一句:这三个工具虽然老,但真的不过时。你想想看,无论日志格式怎么变,核心需求无非就是找、筛、改、统。把这四个动作练熟了,大部分日志分析场景你都能应付。

下一章,咱们聊聊更高级的日志分析框架,比如 ELK 和 Loki。但在此之前,我建议你先动手写几个脚本练练手。毕竟,纸上得来终觉浅嘛。