「零壹运维 · 零到壹,永不宕」
日志是运维的眼睛,是故障排查的第一手证据。面对一个报错、一个异常请求、一个系统崩溃,你能多快定位问题?本文系统梳理 Linux 日志排查四大核心工具,从基础语法到实战场景,帮你建立一套高效的日志分析方法论。
一、日志全景速查表
二、grep — 文本过滤的瑞士军刀
2.1 基本用法
grep <pattern> <file>
核心参数详解
| | |
|---|
-i | | grep -i error app.log |
-v | | grep -v "DEBUG" app.log |
-n | | grep -n "ERROR" app.log |
-c | | grep -c "200 OK" access.log |
-r | | grep -r "ERROR" /var/log/app/ |
-E | | grep -E "ERROR|WARN" app.log |
-B <n> | | grep -B 5 "Exception" app.log |
-A <n> | | grep -A 5 "Exception" app.log |
-C <n> | | grep -C 10 "Exception" app.log |
-f <file> | | grep -f patterns.txt app.log |
--color | | grep --color error app.log |
实战场景
场景1:查找错误日志,显示前后 10 行上下文
grep -C 10 "ERROR" /var/log/app/application.log
场景2:统计 HTTP 请求中 5xx 错误数量
grep -c "5[0-9][0-9]" /var/log/nginx/access.log
场景3:查找多个关键词中的任意一个
grep -E "ERROR|WARN|FATAL" /var/log/app/app.log
场景4:排除 DEBUG 日志,只看 WARN 及以上
grep -v "DEBUG" /var/log/app/app.log | grep -E "WARN|ERROR|FATAL"
场景5:递归查找目录中所有包含 "timeout" 的日志
grep -rn "timeout" /var/log/myapp/
# -r: 递归
# -n: 显示行号
场景6:查找并删除匹配行
grep -v "DELETE" app.log > app.log.tmp && mv app.log.tmp app.log
正则表达式速查
| | |
|---|
^ | | ^ERROR |
$ | | 500$ |
. | | a.c |
* | | ab*c |
[] | | [0-9] |
| | | ERROR|WARN |
\d | | \d+ |
\w | | \w+ |
示例:提取日志中的 IP 地址
grep -oE "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" /var/log/nginx/access.log
# -o: 只输出匹配部分
# -E: 扩展正则
三、awk — 列处理与数据分析
awk 是处理结构化日志的神器,尤其适合分析 Nginx、Apache 等「空格分隔」的日志格式。
3.1 基本语法
awk 'pattern { action }' file
3.2 内置变量
| | |
|---|
$0 | | print $0 |
$1, $2, ... | | print $1, $3 |
NF | | if (NF > 10) |
NR | | NR == 10 |
FS | | BEGIN { FS=":" } |
OFS | | BEGIN { OFS="," } |
3.3 实战场景
场景1:提取 Nginx 日志中的 IP 列
Nginx 默认日志格式:$remote_addr - $remote_user [$time_local] "$request" ...
awk '{print $1}' /var/log/nginx/access.log
场景2:统计每个 IP 的请求次数(Top 10)
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
# 输出:
# 520 192.168.1.100
# 312 192.168.1.200
# 50 10.0.0.1
场景3:统计 HTTP 状态码分布
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
# 输出:
# 15000 200
# 1200 404
# 500 500
场景4:计算平均响应时间(第 6 列)
awk '{sum+=$6} END {print "Avg:", sum/NR, "ms"}' /var/log/app/performance.log
场景5:过滤大于 500ms 的请求
awk '$6 > 500 {print $0}' /var/log/app/performance.log
场景6:自定义分隔符(分析 /etc/passwd)
awk -F: '{print $1, $7}' /etc/passwd
# -F: 指定冒号为分隔符
# 输出:root /bin/bash
场景7:多条件过滤(HTTP 5xx 且响应时间 > 1000ms)
awk '$9 ~ /^5/ && $6 > 1000 {print $0}' /var/log/nginx/access.log
# $9: 状态码
# $6: 响应时间
3.4 awk 高级用法
统计每个 URL 的访问次数
awk -F'"''{print $2}' /var/log/nginx/access.log | awk '{print $2}' | sort | uniq -c | sort -rn | head -10
# -F'": 指定双引号为分隔符
# $2: 请求路径(GET /api/users HTTP/1.1)
统计每个 URL 的平均响应时间
awk '{url[$2]++; time[$2]+=$6} END {for (u in url) print u, time[u]/url[u]}' /var/log/app/performance.log | sort -rnk2
判断字段数量
awk 'NF != 10 {print "Invalid line:", NR}' /var/log/app/app.log
四、sed — 文本编辑与批量处理
sed 是流编辑器,适合批量修改、删除、替换日志内容。
4.1 基本语法
sed [选项] 'command' file
核心参数详解
| | |
|---|
-n | | sed -n '10p' file |
-i | | sed -i 's/foo/bar/' file |
-e | | sed -e 's/foo/bar/' -e 's/baz/qux/' file |
-r | | sed -r 's/[0-9]+/N/' file |
常用命令
| | |
|---|
p | | sed -n '10,20p' file |
d | | sed '10,20d' file |
s/old/new/ | | sed 's/foo/bar/' file |
s/old/new/g | | sed 's/foo/bar/g' file |
实战场景
场景1:替换文件中的字符串(只替换第一个)
sed 's/oldhost/newhost/' /etc/hosts
场景2:全局替换(一行中出现多次)
sed 's/oldhost/newhost/g' /etc/hosts
场景3:直接修改文件(慎用!建议先备份)
sed -i.bak 's/oldhost/newhost/g' /etc/hosts
# -i.bak: 修改前备份为 file.bak
场景4:删除第 10-20 行
sed '10,20d' file.txt
场景5:删除空行
sed '/^$/d' file.txt
场景6:删除包含 "DEBUG" 的行
sed '/DEBUG/d' app.log
场景7:只打印第 5-10 行
sed -n '5,10p' file.txt
场景8:在匹配行后插入内容
sed '/ERROR/a \-- 这是一个错误行 --' app.log
# a: 在匹配行后追加
场景9:在匹配行前插入内容
sed '/ERROR/i \注意:下面是错误日志' app.log
# i: 在匹配行前插入
场景10:批量替换日志中的敏感信息(脱敏)
sed 's/[0-9]{11}/[PHONE_MASKED]/g' /var/log/app/user.log
五、journalctl — systemd 日志查看
journalctl 是 systemd 的日志管理工具,用于查看系统服务日志。
5.1 基本用法
journalctl [选项]
核心参数详解
| | |
|---|
-u <unit> | | journalctl -u nginx |
-f | | journalctl -u nginx -f |
--since | | --since "1 hour ago" |
--until | | --until "2026-03-27 10:00" |
-n <行数> | | -n 100 |
-p <级别> | | -p err |
-k | | -k |
-b | | -b -1 |
日志级别
| |
|---|
emerg | |
alert | |
crit | |
err | |
warning | |
notice | |
info | |
debug | |
实战场景
场景1:查看 Nginx 服务的最近日志
journalctl -u nginx -n 100
场景2:实时跟踪 Nginx 日志
journalctl -u nginx -f
场景3:查看最近 1 小时的错误日志
journalctl --since "1 hour ago" -p err
场景4:查看上次启动的系统日志(排查启动失败)
journalctl -b -1
场景5:查看指定时间段的日志
journalctl --since "2026-03-27 10:00" --until "2026-03-27 12:00"
场景6:只看内核日志(硬件/驱动问题)
journalctl -k -n 100
场景7:过滤包含特定关键词的日志
journalctl -u nginx | grep "ERROR"
场景8:查看 Docker 服务日志
journalctl -u docker
场景9:以 JSON 格式输出(脚本处理)
journalctl -u nginx -o json
六、组合实战:日志排查完整流程
案例一:Nginx 502 错误排查
# Step1:查看 Nginx 错误日志
tail -f /var/log/nginx/error.log
# Step2:查找最近 1 小时的 502 错误
grep "502" /var/log/nginx/access.log | tail -50
# Step3:统计 502 错误的时间分布
grep "502" /var/log/nginx/access.log | awk '{print $4}' | uniq -c | sort -rn
# Step4:查看上游服务日志
journalctl -u myapp --since "1 hour ago" | grep -E "ERROR|WARN"
案例二:应用内存泄漏排查(GC 日志分析)
# Step1:查找 Full GC 日志
grep "Full GC" /var/log/app/gc.log
# Step2:统计 GC 暂停时间(假设格式:[Full GC (Allocation Failure) 1234M->500M(2G), 5.234 ms])
grep "Full GC" /var/log/app/gc.log | grep -oP '\d+\.\d+ ms' | awk -F' ''{sum+=$1} END {print "Total pause:", sum, "ms"}'
# Step3:按时间排序,查看频率变化
grep "Full GC" /var/log/app/gc.log | awk '{print $1, $2}' | sort | uniq -c
案例三:接口响应慢排查
# Step1:找到响应时间 > 1000ms 的请求
awk '$6 > 1000 {print $0}' /var/log/app/performance.log
# Step2:提取慢请求的 URL,统计 Top 10
awk '$6 > 1000 {print $2}' /var/log/app/performance.log | sort | uniq -c | sort -rn | head -10
# Step3:查看慢请求的完整日志上下文
grep "GET /api/slow" /var/log/app/app.log -B 5 -A 5
案例四:批量清理旧日志
# Step1:查找 30 天前的日志
find /var/log/app -name "*.log" -mtime +30
# Step2:查看这些日志的大小
find /var/log/app -name "*.log" -mtime +30 -exec du -sh {} \;
# Step3:压缩旧日志(不删除)
find /var/log/app -name "*.log" -mtime +30 -exec gzip {} \;
# Step4:压缩完成后删除原文件
find /var/log/app -name "*.log.gz" -mtime +60 -delete
七、命令速查卡
# ===== grep =====
grep -i error app.log # 忽略大小写查找
grep -n "ERROR" app.log # 显示行号
grep -C 10 "Exception" app.log # 显示前后 10 行
grep -E "ERROR|WARN" app.log # 或逻辑匹配
grep -v DEBUG app.log | grep ERROR # 排除后过滤
grep -oE "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" access.log # 提取 IP
# ===== awk =====
awk '{print $1}' access.log # 打印第 1 列
awk '{print $1}' access.log | sort | uniq -c | sort -rn # 统计出现次数
awk '$6 > 500 {print $0}' app.log # 过滤第 6 列 > 500
awk -F: '{print $1, $7}' /etc/passwd # 自定义分隔符
# ===== sed =====
sed 's/old/new/g' file.txt # 全局替换
sed -i.bak 's/old/new/g' file.txt # 替换并备份
sed '/^$/d' file.txt # 删除空行
sed -n '10,20p' file.txt # 打印第 10-20 行
# ===== journalctl =====
journalctl -u nginx # 查看 Nginx 服务日志
journalctl -u nginx -f # 实时跟踪
journalctl --since "1 hour ago" -p err # 最近 1 小时错误日志
journalctl -b -1 # 上次启动日志
八、最佳实践总结
| |
|---|
| 先用 grep 定位,再用 awk 分析 | |
用 -C 查上下文 | |
| 批量操作先备份 | sed -i |
实时跟踪用 -f | tail -f |
| |
| 正则从简单到复杂 | |
| 日志规范很重要 | |
九、小结
| | |
|---|
| grep | | grep -C 10 "ERROR" app.log |
| awk | | awk '{print $1}' | sort | uniq -c | sort -rn |
| sed | | sed -i 's/old/new/g' file |
| journalctl | | journalctl -u nginx -f |
核心原则:
「日志就是证据,先定位时间,再过滤关键词,最后用 awk 做统计。」
「零壹运维 · 零到壹,永不宕」
系列导航
- 上一篇:《Linux 网络诊断工具箱:ping/traceroute/ss/tcpdump/curl 深度解析》
- 下一篇:《Linux 磁盘排查与清理实战:du/df/lsof/find 完全手册》(即将发布)