日志管理:journald、logrotate 与日志该放哪

日志是排错时唯一的线索来源,但它也是把磁盘写满的头号嫌疑。这篇讲清楚日志往哪去、怎么看、怎么管。

一、两套日志系统

现代 Linux 有两套并存的日志:

系统位置管什么
systemd-journald二进制,/var/log/journal所有服务的 stdout/stderr + 结构化字段
rsyslog文本,/var/log/*.log传统 syslog,按 facility 分文件

简单理解:用 systemd 跑的服务看 journalctl,Nginx 这类自己写文件的看 /var/log/nginx/

bash
# journald 是否持久化(默认有些发行版只存内存)
ls /var/log/journal
# 目录不存在说明只存内存,重启就没了

# 打开持久化
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

二、journalctl 高频用法

bash
# 看某个服务
journalctl -u nginx
journalctl -u nginx -f                      # 实时跟随
journalctl -u nginx -n 100 --no-pager       # 最近 100 行,不分页

# 按时间
journalctl --since "2026-02-19 10:00" --until "11:00"
journalctl --since "30 min ago"
journalctl --since today
journalctl --since yesterday --until today

# 按优先级
journalctl -p err -b                        # 本次启动的所有错误
journalctl -p warning --since today
# 级别:emerg(0) alert crit err warning notice info debug

# 按启动次数
journalctl -b                               # 本次启动
journalctl -b -1                            # 上一次启动(排查崩溃必备)
journalctl --list-boots

# 按进程/用户
journalctl _PID=1234
journalctl _UID=1000

# 输出格式
journalctl -u nginx -o json-pretty
journalctl -u nginx -o cat                  # 只要正文

# 反向显示(最新的在前)
journalctl -u nginx -r -n 50

三、控制 journald 的体积

bash
journalctl --disk-usage                     # 看占了多少

# 按大小清理
sudo journalctl --vacuum-size=500M
# 按时间清理
sudo journalctl --vacuum-time=14d
# 按文件数清理
sudo journalctl --vacuum-files=5

永久配置 /etc/systemd/journald.conf

nginx
[Journal]
SystemMaxUse=500M          # 最大占用
SystemKeepFree=1G          # 至少给磁盘留这么多
MaxRetentionSec=1month     # 最多保留一个月
Compress=yes
bash
sudo systemctl restart systemd-journald

四、logrotate:管住文本日志

Nginx 的日志是 rsyslog 之外的独立文件,由 logrotate 定期轮转。

bash
cat /etc/logrotate.d/nginx
nginx
/var/log/nginx/*.log {
    daily                  # 每天轮转
    rotate 14              # 保留 14 份
    compress               # 压缩(.gz)
    delaycompress          # 延迟一轮再压(避免程序还握着文件)
    missingok              # 文件不存在不报错
    notifempty             # 空文件不轮转
    create 0640 www-data adm
    sharedscripts          # 多个文件只执行一次脚本
    postrotate
        [ -f /run/nginx.pid ] && kill -USR1 $(cat /run/nginx.pid)
    endscript
}

关键参数:

参数作用
daily/weekly/monthly轮转周期
rotate N保留几份
size 100M达到大小就轮转(可与时间并存)
compressgzip 压缩
copytruncate复制后清空原文件(程序不支持 reopen 时用)
postrotate轮转后执行的命令

调试与验证:

bash
sudo logrotate -d /etc/logrotate.d/nginx    # 调试模式,只显示会做什么
sudo logrotate -f /etc/logrotate.d/nginx    # 强制执行一次
cat /var/lib/logrotate/status               # 上次轮转时间

五、自己写的日志也要轮转

备份脚本、应用日志很容易被忘掉。加一份配置:

nginx
# /etc/logrotate.d/baize
/var/log/baize/*.log {
    weekly
    rotate 8
    compress
    missingok
    notifempty
    create 0640 baize baize
}

六、日志里该记什么

一条好日志至少要有:时间、级别、谁、发生了什么

bash
# 一个够用的日志函数
log() { echo "[$(date '+%F %T')] [$${1:-INFO}] $*" >> /var/log/baize/app.log; }
log INFO "备份开始"
log ERROR "数据库连接失败"

几个原则:

  • 别记密码、token、身份证号(日志泄露是最常见的数据事故);
  • 错误日志要带上下文(哪个用户、哪个 ID),否则没法查;
  • 别把日志打到 stdout 又同时写文件,会重复;
  • 结构化(JSON)日志便于后续分析,但小项目没必要。

七、看日志的实用组合

bash
# 统计访问日志里的 TOP IP
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

# 找 5xx 请求
awk '$9 >= 500' /var/log/nginx/access.log | head -20

# 找耗时最长的请求(最后一列是响应时间)
awk '{print $NF, $7}' /var/log/nginx/access.log | sort -rn | head -10

# 某个时间段的日志
sed -n '/19/Feb/2026:10:00/,/19/Feb/2026:11:00/p' /var/log/nginx/access.log

# 实时看错误(只看新增)
tail -f /var/log/nginx/error.log

八、保留策略建议

类型保留期理由
访问日志7~30 天量大,够排查就行
错误日志30~90 天体积小,价值高
安全日志(auth.log)90 天以上审计需要
应用业务日志按需

日志策略就两条:磁盘别被写满,出事时查得到。