为什么要看日志?

有一次网站突然502错误,我急得满头大汗,最后是看日志才发现是MySQL连接数超限。如果早看日志,5分钟就解决了。

日志是服务器的”黑匣子”,几乎所有问题都能从日志里找到线索。


日志文件位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/var/log/                        # 主要日志目录
├── auth.log # 登录日志
├── syslog # 系统日志
├── kern.log # 内核日志
├── messages # 通用消息
├── nginx/ # Nginx日志
│ ├── access.log # 访问日志
│ └── error.log # 错误日志
├── mysql/ # MySQL日志
│ └── error.log
├── apache2/ # Apache日志
│ ├── access.log
│ └── error.log
└── docker/ # Docker日志(可能不在这里)

tail - 实时查看日志

tail是查看日志的神器,尤其适合看实时日志。

基本用法

1
2
3
4
5
6
7
8
# 查看最后10行
tail /var/log/syslog

# 查看最后100行
tail -n 100 /var/log/syslog

# 实时查看(最常用!)
tail -f /var/log/syslog

故事:有一次我要等一个用户操作,用户说”我点了”,我看不到日志,急得团团转。后来才知道要用 tail -f 实时看,而不是每次都 cat 整个文件。

实时查看多文件

1
2
# 同时看多个日志
tail -f /var/log/nginx/access.log /var/log/nginx/error.log

查看特定时间段的日志

1
2
# 查看文件变更后新增的日志
tail -F -n 200 /var/log/syslog # -F 会检测文件轮转

journalctl - systemd日志(推荐)

systemd的日志比传统 /var/log/ 更好,支持查询、过滤,不需要切换不同文件。

基本查询

1
2
3
4
5
6
7
8
# 查看所有日志
journalctl

# 查看最近的日志
journalctl -n 50

# 实时查看
journalctl -f

查看特定服务

1
2
3
4
5
6
7
8
# 查看Nginx日志
journalctl -u nginx

# 查看MySQL日志
journalctl -u mysql

# 查看特定PID
journalctl _PID=1234

时间过滤

1
2
3
4
5
6
7
8
9
10
11
# 查看今天的日志
journalctl --since today

# 查看昨天的
journalctl --since yesterday --until today

# 查看最近30分钟的
journalctl --since "30 minutes ago"

# 查看特定时间段
journalctl --since "2024-02-13 10:00" --until "2024-02-13 12:00"

优先级过滤

1
2
3
4
5
6
7
# 只看错误和警告
journalctl -p err -p warning

# 优先级从高到低:emerg, alert, crit, err, warning, notice, info, debug
journalctl -p err # 紧急
journalctl -p warning # 警告
journalctl -p notice # 通知

只看某个用户的日志

1
2
journalctl _UID=1000               # 用户ID 1000
journalctl _SYSTEMD_USER_UNIT=user@

持久化journal日志

默认日志只在内存,重启会丢失。持久化:

1
2
3
4
5
6
7
8
# 创建目录
mkdir -p /var/log/journal

# 设置权限
systemd-tmpfiles --create --prefix /var/log/journal

# 重启服务
systemctl restart systemd-journald

grep - 搜索日志内容

grep是搜索大王,用它能在海量日志中快速找到问题。

基本搜索

1
2
3
4
5
6
7
8
# 搜索关键词
grep "error" /var/log/nginx/error.log

# 搜索多个关键词(或)
grep -E "error|warning" /var/log/syslog

# 搜索多个关键词(且)
grep "error" /var/log/syslog | grep "database"

实时搜索

1
2
# 实时显示包含error的日志行
tail -f /var/log/syslog | grep "error"

显示行号和上下文

1
2
3
4
5
6
7
8
9
10
11
# 显示行号(方便定位)
grep -n "error" /var/log/syslog

# 显示匹配行及其前后2行
grep -C 2 "error" /var/log/syslog

# 只显示后2行
grep -A 2 "error" /var/log/syslog

# 只显示前2行
grep -B 2 "error" /var/log/syslog

忽略大小写

1
grep -i "Error" /var/log/syslog     # 同时匹配error和Error

统计匹配次数

1
grep -c "error" /var/log/nginx/error.log

反向搜索

1
2
# 查看不含error的行
grep -v "error" /var/log/syslog

组合拳:常用查询场景

场景1:网站502错误,快速排错

1
2
3
4
5
6
7
8
# 1. 查看Nginx错误日志
tail -n 100 /var/log/nginx/error.log

# 2. 搜索502
grep "502" /var/log/nginx/error.log

# 3. 查看相关时间段的系统日志
journalctl --since "10 minutes ago" | grep -E "nginx|mysql|php"

场景2:查看谁登录过服务器

1
2
3
4
5
6
7
8
# 查看认证日志
grep "Accepted" /var/log/auth.log

# 查看登录失败的
grep "Failed" /var/log/auth.log

# 实时监控登录
tail -f /var/log/auth.log | grep "Failed"

场景3:Docker容器日志

1
2
3
4
5
6
7
8
9
10
11
# 查看容器日志
docker logs container_name

# 实时查看
docker logs -f container_name

# 只看最近200行
docker logs --tail 200 container_name

# 查看特定时间之后的
docker logs --since 2024-02-13T10:00 container_name

场景4:排查磁盘爆满

1
2
3
4
5
# 查找大文件日志
find /var/log -name "*.log" -size +100M

# 找出占用磁盘最多的目录
du -h --max-depth=1 /var/log | sort -hr

日志分析工具推荐

手写grep太累?试试工具:

1. multitail

同时监控多个日志,彩色输出:

1
2
3
apt install -y multitail

multitail /var/log/nginx/access.log /var/log/nginx/error.log

2. lnav

自动解析日志,支持搜索、高亮:

1
2
3
apt install -y lnav

lnav /var/log/nginx/error.log

3. journalctl -o json

输出JSON格式,方便脚本处理:

1
journalctl -o json | jq

踩坑经验

坑1:tail -f 不显示新日志

  • 可能是日志轮转了(文件被重命名)
  • 解决:用 tail -F(大写F)

坑2:journalctl日志太多看不过来

  • 按时间或服务过滤,聚焦问题点

坑3:日志文件太大打不开

  • 不要 cat 整个文件,用 tailhead
  • 或者分割文件:split -l 1000000

坑4:日志没有时间戳

  • 某些应用配置问题,检查日志格式设置

日志管理最佳实践

1. 定期清理

1
2
# 清理30天前的日志
find /var/log -name "*.log" -mtime +30 -delete

2. 配置logrotate

系统自动轮转日志:

1
2
# 查看 nginx 配置
cat /etc/logrotate.d/nginx

3. 配合监控告警

1
2
3
4
# 检测错误数量,超过阈值发告警
tail -f /var/log/app.log | grep --line-buffered "ERROR" | awk 'END{print NR}' | while read count; do
[ "$count" -gt 100 ] && echo "告警:错误过多!"
done

总结

  • tail -f - 实时查看,等待问题出现时用
  • journalctl - systemd的现代化日志,支持查询过滤
  • grep - 搜索关键词,快速定位
  • 常用组合:journalctl -u 服务名 | grep error
  • 时间过滤:--since--until 帮你找到发生问题的时刻
  • 高级工具:multitaillnav 提升效率
  • 日志要及时清理,避免占满磁盘
  • 配合监控,出问题自动告警

下一篇:Docker部署个人博客实战。