【前情提要】logrotate 配好了,日志自动切割了,磁盘告警也不会再因为日志暴涨而频繁触发了。老周说:“监控告警项目做完了,但你有没有发现,你每天还是在手动查日志?”小林点头。老周说:“明天开始,第三个项目:日志分析。”
一、告警的“疲劳轰炸”
周一早上,小林打开邮箱,傻眼了。
收件箱里躺着 47 封告警邮件:
[FIRING:1] HighCpuUsage (warning)
[FIRING:1] HighMemoryUsage (warning)
[FIRING:1] InstanceDown (critical)
[RESOLVED] HighCpuUsage
[FIRING:1] HighDiskUsage (warning)
[RESOLVED] HighDiskUsage
[FIRING:1] HighCpuUsage (warning)
...
“周哥,我邮箱爆了。”
老周走过来看了一眼:“你配了几条告警?”
“CPU、内存、磁盘、服务离线……六七条吧。”
“六七条告警,一周 47 封邮件。”老周说,“你知道问题在哪吗?”
小林摇头。
“告警告诉你‘出事了’,但没告诉你‘为什么出事’。 你收到 HighCpuUsage,只知道 CPU 高,但不知道为什么高。你收到 InstanceDown,只知道服务挂了,但不知道为什么挂。”
“那怎么知道为什么?”
“看日志。”老周说,“告警是‘症状’,日志是‘病历’。你得从病历里找病因。”
小林在笔记本上写下:
- 告警:症状,告诉你“出事了”
- 日志:病历,告诉你“为什么出事”
二、日志的三种类型
“你现在接触过哪些日志?”老周问。
小林想了想:“Nginx 的 access.log 和 error.log。”
“对,这是两种。还有第三种:系统日志。”
老周拿过小林的笔记本,画了一个表。
| 类型 |
文件 |
内容 |
用途 |
| 访问日志 |
/var/log/nginx/access.log |
谁访问了什么 |
分析流量、Top IP、Top URL |
| 错误日志 |
/var/log/nginx/error.log |
Nginx 自身的错误 |
排查 500、502、404 |
| 系统日志 |
/var/log/syslog |
系统事件、服务状态 |
排查服务崩溃、登录失败 |
“你之前用过 access.log 和 error.log。”老周说,“但 syslog 你还没碰过。打开看看。”
sudo tail -20 /var/log/syslog
输出:
Sep 14 10:00:01 ubuntu systemd[1]: Starting Daily apt upgrade...
Sep 14 10:00:02 ubuntu systemd[1]: Started Daily apt upgrade.
Sep 14 10:05:23 ubuntu sshd[1234]: Accepted publickey for devops from 192.168.1.100 port 54321 ssh2
Sep 14 10:10:45 ubuntu kernel: [12345.678] nginx[1236]: segfault at ...
“syslog 记录所有系统事件。”老周说,“服务启动、SSH 登录、内核报错、定时任务,都在这。”
“那 journalctl 呢?”
“journalctl 是 systemd 的日志工具,看的是 journal,不是 syslog。journal 是二进制格式,syslog 是文本格式。你入门阶段,先用 syslog,因为它是文本,能直接用grep和awk处理。”
小林记下:
- access.log:访问日志,分析流量
- error.log:错误日志,排查 Nginx 错误
- syslog:系统日志,排查系统事件
- journalctl:systemd 日志,二进制格式
三、日志分析的三个层次
“现在讲方法。”老周说,“日志分析分三个层次:看、筛、析。”
第一层:看。
“你得知道日志长什么样,有哪些字段。用 head、tail、wc -l 看。”
sudo head -5 /var/log/nginx/access.log
sudo tail -5 /var/log/nginx/access.log
sudo wc -l /var/log/nginx/access.log
第二层:筛。
“从大量日志里,筛出你关心的部分。用 grep 过滤关键词,用 awk 提取字段。”
sudo grep " 500 " /var/log/nginx/access.log
sudo awk '$9 == 500' /var/log/nginx/access.log
第三层:析。
“从筛出来的日志里,提取统计信息。用 sort、uniq -c、awk 统计。”
sudo awk '$9 == 500 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort-rn | head -10
“这三个层次,是你以后做日志分析的基本流程。”老周说,“先看,再筛,后析。”
小林记下:
- 看:head、tail、wc -l
- 筛:grep、awk
- 析:sort、uniq -c、awk
四、grep、awk、sed 的角色
“你之前用过 grep 和 awk,但没系统学过。”老周说,“今天我给你讲清楚,这三个工具在日志分析里,各干什么。”
grep:过滤行。
“grep 按行过滤。你给它一个模式,它找出匹配的行。日志分析里,grep 用来‘快速缩小范围’。”
sudo grep" 500 " /var/log/nginx/access.log
sudo grep"^192.168.1.100" /var/log/nginx/access.log
sudo grep"/api/health" /var/log/nginx/access.log
awk:处理列。
“awk 按列处理。你给它一个规则,它提取、计算、统计。日志分析里,awk 用来‘按字段统计’。”
sudo awk'{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort-rn | head
sudo awk'$9 == 500 {print $7}' /var/log/nginx/access.log
sed:修改文本。
“sed 按行修改。你给它一个替换规则,它改内容。日志分析里,sed 用来‘脱敏、提取、转换’。”
sudo sed 's/192.168.1.100/***.***.***.***/g' /var/log/nginx/access.log
sudo sed -n '100,200p' /var/log/nginx/access.log
“总结一下:”
- grep:按行过滤,缩小范围
- awk:按列处理,提取统计
- sed:按行修改,脱敏转换
“你以后分析日志,就是这三个工具的组合。”老周说,“grep 先筛,awk 再算,sed 最后改。管道串起来,就是一条完整的分析命令。”
小林在笔记本上写下:
grep 筛行 → awk 算列 → sed 改内容
五、概念排错挑战:给定日志,你会用哪条命令?
老周从桌上拿了一张纸,写了一段日志:
192.168.1.100 - - [14/Sep/2026:10:00:01 +0800] "GET / HTTP/1.1" 200 1234 "-" "Mozilla/5.0"
192.168.1.101 - - [14/Sep/2026:10:00:02 +0800] "GET /posts/my-first-post/ HTTP/1.1" 200 2345 "-" "Mozilla/5.0"
192.168.1.100 - - [14/Sep/2026:10:00:03 +0800] "GET /api/health HTTP/1.1" 500 153 "-" "curl/7.81.0"
192.168.1.102 - - [14/Sep/2026:10:00:04 +0800] "GET /images/missing.png HTTP/1.1" 404 153 "-" "Mozilla/5.0"
192.168.1.100 - - [14/Sep/2026:10:00:05 +0800] "POST /api/login HTTP/1.1" 500 200 "-" "curl/7.81.0"
“现在,我问你五个问题。你口述用哪条命令。”
问题一:找出所有状态码为 500 的请求。
小林想了想:“awk '$9 == 500'。”
“对。但也可以用 grep。”
sudo grep" 500 " /var/log/nginx/access.log
问题二:找出所有来自192.168.1.100的请求。
“grep "^192.168.1.100"。”
问题三:统计每个 IP 的请求数。
awk '{print $1}' | sort | uniq -c | sort -rn
问题四:找出所有 500 请求的 URL。
awk '$9 == 500 {print $7}'
问题五:把日志里的 IP 替换为***。
sed 's/192.168.1.[0-9]*/***/g'
老周点头:“五个问题,五个命令。你以后分析日志,就是这些套路。先想清楚要什么,再选工具。”
六、看日志的基本命令
“现在实战。”老周说,“你先用 head、tail、wc -l 看日志基本信息。”
小林敲:
sudo wc -l /var/log/nginx/access.log
输出:
50000 /var/log/nginx/access.log
“5 万行。”小林说。
sudo head -5 /var/log/nginx/access.log
输出前 5 行。
sudo tail -5 /var/log/nginx/access.log
输出最后 5 行。
“你还可以看文件大小。”
sudo ls -lh /var/log/nginx/access.log
输出:
-rw-r----- 1 www-data adm 8.3M Sep 14 10:00 /var/log/nginx/access.log
“8.3M,5 万行。”老周说,“这就是你现在的日志量。你以后每天分析,先看这三个数:行数、首行、末行。行数告诉你数据量,首行末行告诉你时间范围。”
“那 wc -l 和 wc -c 有啥区别?”
“-l 是行数,-c 是字节数,-w 是单词数。”老周说,“你分析日志,主要看行数。”
小林记下:
- wc -l:统计行数
- head -N:看前 N 行
- tail -N:看后 N 行
- ls -lh:看文件大小
七、排错挑战:grep 结果太多
下午,小林想找出所有 404 的请求。
sudo grep" 404 " /var/log/nginx/access.log
终端刷了几千行,根本停不下来。
“太多了。”小林按了 Ctrl+C。
他喊来老周。
“grep 结果太多,怎么办?”
“四个办法。”老周竖起四根手指。
第一, -c 只统计数量。
sudo grep -c " 404 " /var/log/nginx/access.log
输出:
1523
“1523 个 404。”小林说。
第二, | head 只看前几条。
sudo grep " 404 " /var/log/nginx/access.log | head -10
第三, | wc -l 统计行数(和-c类似)。
sudo grep" 404 " /var/log/nginx/access.log | wc-l
第四,用 awk 统计哪些 URL 404 最多。
sudo awk '$9 == 404 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort-rn | head -10
输出:
500 /api/health
300 /images/missing.png
200 /posts/old-post/
100 /favicon.ico
“看到了吗?”老周说,“grep是‘筛’,不是‘析’。你要统计,得用awk+sort+uniq。 光 grep 刷屏,没用。”
排错思路总结:
- grep 结果太多,先 Ctrl+C 停掉。
- 用 grep -c 统计数量。
- 用 grep | head 看前几条。
- 用 grep | wc -l 统计行数。
- 想统计分布,用 awk + sort + uniq -c + sort -rn。
- grep负责筛,awk负责析。别用grep做统计。
“记住,”老周说,“日志分析的核心不是‘看’,是‘算’。 你 grep 出来的行,要交给 awk 去算,才能得出结论。”
八、练习
- 练习一:用 wc -l 查看 /var/log/nginx/access.log 的总行数,用 head -5 和 tail -5 查看首尾日志,用 ls -lh 查看文件大小。把这三个信息记录到 ~/log_basic_info.txt。
- 练习二:用 grep -c 统计 access.log 中状态码为 200、404、500 的请求各有多少条。用 grep " 500 " | head -5 查看前 5 条 500 请求。
- 练习三:用 awk '$9 == 500 {print$7}' | sort | uniq -c | sort -rn | head -10 统计 500 请求最多的 URL。然后用 grep "/api/" access.log | head -10 查看包含 /api/ 的请求。
参考答案
练习一:
{
echo "=== 总行数 ==="
sudo wc -l /var/log/nginx/access.log
echo "=== 前 5 行 ==="
sudo head -5 /var/log/nginx/access.log
echo "=== 后 5 行 ==="
sudo tail -5 /var/log/nginx/access.log
echo "=== 文件大小 ==="
sudo ls -lh /var/log/nginx/access.log
} > ~/log_basic_info.txt
cat ~/log_basic_info.txt
练习二:
sudo grep -c" 200 " /var/log/nginx/access.log
sudo grep -c" 404 " /var/log/nginx/access.log
sudo grep -c" 500 " /var/log/nginx/access.log
sudo grep " 500 " /var/log/nginx/access.log | head -5
练习三:
sudo awk '$9 == 500 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort-rn | head -10
sudo grep "/api/" /var/log/nginx/access.log | head -10
九、下集预告
日志分析的三个层次讲清楚了,grep、awk、sed 的角色也分清了。老周说:“明天开始,一个一个练。先练 grep,它是你筛日志的第一把刀。”小林打开 grep 的 man 手册,准备学参数。但他不知道,-c、-n、-v、-i、-E、-A/-B/-C,每一个都有用。
下一集:《grep 实战:在 10 万行日志里找一根针》
更多 Linux 日志分析实战笔记,欢迎来云栈社区一起交流。