前言
“昨晚服务为什么挂了?"——答案 90% 藏在日志里。现代 Linux 有两套并行的日志体系:传统 rsyslog(写文件)与 systemd-journald(二进制数据库)。搞懂它们,排障效率翻倍。
一、日志全景图
应用程序 ──┬─► /dev/log ──► systemd-journald ──► /run/log/journal(二进制, 易失)
│ │
│ └──► 转发 ──► rsyslog ──► /var/log/*.log(文本文件)
│
└─► 自己直接写文件(如 nginx access.log)
- journald:systemd 全家桶,统一收集,按索引查询,默认重启丢失(可开持久化)
- rsyslog:老牌守护进程,按规则分类写入文本文件,方便 grep/tail
二、journald 使用
journalctl # 全部日志(分页)
journalctl -u nginx # 某服务
journalctl -u nginx -f # 实时跟踪
journalctl -n 100 # 最近 100 行
journalctl -b # 本次开机以来
journalctl -b -1 -e # 上次开机(跳到末尾)—— 查"为什么重启"神器
journalctl --since "2023-12-01" --until "2023-12-02 03:00"
journalctl -p err..alert # 按严重级别过滤
journalctl _PID=8642 # 按进程
journalctl -k # 仅内核日志
journalctl --disk-usage # 占用
journalctl --vacuum-size=500M # 收缩
开启持久化(默认存内存,重启即丢):
mkdir -p /var/log/journal
systemctl restart systemd-journald
# 之后重启, journalctl -b -1 就能查上次开机的日志了
三、rsyslog 与经典日志文件
rsyslog 规则格式:facility.severity 动作
- facility(来源):kern、auth、cron、daemon、mail、local0-7(自定义)……
- severity(级别):debug < info < notice < warning < err < crit < alert < emerg
grep -v "^#" /etc/rsyslog.conf | grep -v "^$" # 看生效规则
tail -f /var/log/messages # 通用消息(RHEL 系主战场)
tail -f /var/log/secure # 认证相关: SSH 登录成功/失败都在这
grep "Accepted" /var/log/secure # 谁成功登录过
grep "Failed password" /var/log/secure | wc -l # 被爆破次数
tail -f /var/log/cron # 定时任务执行记录
dmesg -T # 内核环形缓冲(硬件、OOM 杀进程)
自定义应用日志接入(写个 local facility):
# /etc/rsyslog.d/myapp.conf
local6.* /var/log/myapp.log
systemctl restart rsyslog
# 应用里: logger -p local6.info "app started"
四、logrotate:日志轮转
日志不管理迟早撑爆磁盘。logrotate 按策略切割/压缩/删除:
cat /etc/logrotate.conf # 主配置
ls /etc/logrotate.d/ # 各软件的子配置
给自家应用写一个 /etc/logrotate.d/myapp:
/var/log/myapp/*.log {
daily # 每天轮转
rotate 14 # 保留 14 份历史
missingok # 文件不存在不报错
notifempty # 空文件不轮转
compress # 压缩旧日志
delaycompress # 延迟一天压缩(最新的还能直接看)
dateext # 文件名带日期: app.log-20231202.gz
copytruncate # 复制后截断原文件(应用无需重开文件句柄)
sharedscripts
postrotate
[ -f /var/run/myapp.pid ] && kill -USR1 $(cat /var/run/myapp.pid)
endscript
}
copytruncatevspostrotate发信号:前者简单粗暴但可能丢极少量日志;后者优雅但要求应用支持重开日志文件(如 nginx 的USR1)。
logrotate -d /etc/logrotate.d/myapp # dry-run 演练, 不真动文件
logrotate -f /etc/logrotate.d/myapp # 强制立即执行一次
五、排障套路:从日志找线索
# 1. 时间线: 出问题的时间点前后, 系统层有什么动静
journalctl --since "10:00" --until "10:30" -p warning
# 2. 资源杀手: OOM 会在内核日志留痕
dmesg -T | grep -i -E "oom|killed process"
journalctl -k | grep -i oom
# 3. 登录审计: 半夜有没有人动过机器
last | head # 登录历史
lastb | head # 失败的登录
grep "session opened" /var/log/secure
# 4. 磁盘: 是不是日志自己把盘写满了
du -sh /var/log
find /var/log -size +100M -exec ls -lh {} \;
六、实践建议
| 做法 | 说明 |
|---|---|
| journald 开持久化 | /var/log/journal 目录一建就行 |
| 应用日志统一目录 | /var/log/appname/,别散落在家目录 |
| 每个应用配 logrotate | 用 copytruncate 起步最省心 |
| cron 任务输出重定向 | 否则邮件堆爆 /var/spool/mail |
| 集中收集 | 单机方案之上,后续上 ELK/Loki(后面写文章) |
小结
- journald 管 systemd 生态(
journalctl -u一把梭),rsyslog 管文本文件(好 grep 好归档) - 排障三板斧:
journalctl --since、dmesg -T、/var/log/secure - 日志三防:轮转(logrotate)、限额(journald vacuum)、集中(ELK)
本文是「Linux 运维」系列第 5 篇。