Skip to content

日志管理

系统排障主要依赖三类日志来源:systemd journald(服务日志)、rsyslog(传统系统日志)、应用自身写的文件日志。

一、日志目录和文件

大多数系统和服务的日志集中在 /var/log 下。

文件对应发行版内容
/var/log/messagesRHEL 系通用系统日志
/var/log/syslogDebian/Ubuntu通用系统日志
/var/log/secureRHEL 系认证和安全相关日志(SSH 登录、sudo 等)
/var/log/auth.logDebian/Ubuntu认证和安全相关日志
/var/log/dmesg通用内核启动日志的快照
/var/log/cron部分发行版cron 执行日志

不同的发行版日志文件名不完全相同,排查时先确认目标发行版的命名习惯。遇到登录相关问题看 secureauth.log,内核和硬件问题看 dmesg

二、journald 和 journalctl

systemd 的日志系统叫 journald。它收拢了 systemd 管理服务的 stdout/stderr、内核日志和部分系统日志,存放在二进制格式的日志文件中(而不是纯文本),查询时使用 journalctl

bash
journalctl                        # 查看全部日志(可能非常多)
journalctl -u nginx               # 只看指定 unit 的日志
journalctl -u nginx -f            # 持续跟踪,类似 tail -f
journalctl -u nginx --since "1 hour ago"
journalctl -p err                 # 只看 error 级别及以上的日志

常用参数:

参数作用
-u过滤指定 systemd unit
-f持续输出新日志(follow)
--since起始时间(支持 "today"、"1 hour ago"、"2026-05-21")
--until结束时间
-p按日志级别过滤(emerg、alert、crit、err、warning、notice、info、debug)
-n显示最近 N 行
--no-pager不使用分页直接输出,方便脚本处理

服务启动失败的标准排查:

bash
systemctl status app --no-pager           # 看状态和最后几行日志
journalctl -u app -n 100 --no-pager       # 看最近 100 行

从最近日志开始看,再按时间逐渐扩大范围。一上来就翻全量日志效率很低。

journald 的持久化行为与 /var/log/journal 目录是否存在有关。如果该目录不存在,journald 默认只在 /run/log/journal(tmpfs,内存中)存储日志,重启后日志丢失。需要持久化时:

bash
mkdir -p /var/log/journal
systemctl restart systemd-journald

三、rsyslog

rsyslog 是传统的系统日志服务,负责按规则将不同来源的日志写到对应的文本文件中。journald 和 rsyslog 可以同时存在——journald 收集,再通过转发交给 rsyslog 归档。

主配置和附加配置:

bash
cat /etc/rsyslog.conf
ls /etc/rsyslog.d/

重启 rsyslog:

bash
systemctl restart rsyslog

rsyslog 的规则格式是 facility.level 目标

conf
*.info;mail.none;authpriv.none;cron.none    /var/log/messages
authpriv.*                                  /var/log/secure
cron.*                                      /var/log/cron

facility 表示日志来源类别(authpriv=认证、cron=定时任务、mail=邮件、daemon=守护进程),level 表示记录的最低等级。authpriv.* 表示认证相关的所有级别的日志都写入 /var/log/secure

一般的应用服务不直接修改 rsyslog 配置。只有当需要做集中日志收集、自定义日志路径或调整系统日志行为时才会动它。

四、dmesg 内核日志

dmesg 查看内核环形缓冲区中的消息,包含硬件探测、驱动加载、OOM killer、网络接口状态等信息。

bash
dmesg
dmesg -T                     # 显示可读时间戳
dmesg -T | tail -n 50

过滤异常信息:

bash
dmesg -T | grep -i -E "error|fail|oom|reset"

磁盘 I/O 错误、网卡 link down、OOM 被杀进程、USB 设备异常等都可以在 dmesg 里找到痕迹。需要注意 dmesg -T 显示的时间在某些系统上可能不准——内核的时间戳和系统时间不一定同步,关键事故还是要结合 journald 和其他日志交叉验证。

五、logrotate 日志轮转

logrotate 解决的是日志文件无限增长的问题。它不减少日志量,只是定期把旧日志改名、压缩、删除。

bash
cat /etc/logrotate.conf              # 全局配置
ls /etc/logrotate.d/                 # 各服务的独立配置

一个典型的轮转配置:

logrotate
/var/log/myapp/*.log {
    daily                    # 每天轮转一次
    rotate 7                 # 保留最近 7 份
    missingok               # 文件不存在不报错
    notifempty              # 空文件不轮转
    compress                # 压缩旧日志
    delaycompress           # 延迟压缩(保留最近一份不压缩,方便仍在查)
    copytruncate            # 拷贝后清空原文件
}

copytruncate 的方式:先把日志内容复制到轮转文件,再清空原日志文件。优点是不需要服务支持重新打开日志文件,缺点是复制和清空之间产生的少量日志可能丢失。

对于支持 reload 信号的服务(如 nginx),更可靠的方式是 postrotate

logrotate
/var/log/nginx/*.log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    postrotate
        systemctl reload nginx >/dev/null 2>&1 || true
    endscript
}

轮转完成后发 reload 信号给服务,让服务重新打开日志文件。这比 copytruncate 更可靠,不会丢日志。

测试配置:

bash
logrotate -d /etc/logrotate.conf      # -d 是 debug 模式,只模拟不执行
logrotate -f /etc/logrotate.conf      # -f 强制执行一次

正式强制轮转前先用 -d 模拟跑一遍,特别是带 postrotate--delete 的配置。

六、日志排查的基本方法

按时间范围定位:

bash
journalctl --since "2026-05-21 10:00:00" --until "2026-05-21 11:00:00"

按关键字过滤:

bash
grep -i "error" app.log
grep -i -E "error|exception|failed|timeout" app.log

关注日志增长速度:

bash
ls -lh app.log              # 单个文件大小
du -sh /var/log/*           # 各日志目录占用
tail -f app.log             # 观察写入速度

日志目录单独挂载是一个简单的防护措施。应用程序异常狂写日志时,不至于把根分区打满进而影响整个系统。