Nginx 本身不支持按天自动切分日志,需要通过外部工具实现。最常用的方法是 logrotate(linux系统自带日志轮转工具),也可以使用 cron 脚本配合 nginx -s reopen 实现。
方法一:使用 logrotate(推荐)
大多数 Linux 发行版安装 Nginx 后会自动创建 /etc/logrotate.d/nginx 配置文件,默认按天轮转。(如果没有需手动创建该文件)
1. 检查现有配置
cat /etc/logrotate.d/nginx
2. 典型配置示例
# *.log日志路径和nginx.pid文件路径根据自己的实际情况配置
/usr/local/nginx/logs/*.log {
daily # 按天轮转
missingok # 日志不存在时不报错
rotate 30 # 保留30天
dateext # 启用日期后缀
compress # 压缩旧日志
delaycompress # 延迟压缩(保留最近一个未压缩)
notifempty # 空文件不轮转
# create:指示 logrotate 在轮转(重命名/压缩)旧日志后,创建一个新的空日志文件。
# 0640 表示:
# 所有者(nginx 用户):读、写(6 = rw-)
# 所属组(adm 组):读(4 = r--)
# 其他人:无任何权限(0 = ---)
# 即最终权限为 -rw-r-----
# nginx:新文件的所有者(用户)。通常 Nginx 进程以 nginx 用户运行,这样进程才能写入该日志文件。
# adm:新文件的所属组。adm 组在 Linux 中常用于系统日志管理,允许属于该组的用户(如管理员)读取日志。
create 0640 nginx adm
sharedscripts
postrotate
# 重新打开日志文件,注意信号是 USR1 或 reopen
[ -f /usr/local/nginx/logs/nginx.pid ] && kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
endscript
}
postrotate / endscript 含义:定义一个在日志轮转之后执行的脚本块。postrotate开始,endscript结束。脚本可以是任何 Shell 命令。
sharedscripts 含义:指示 logrotate 对所有匹配的日志文件只执行一次 postrotate 中的脚本,而不是为每个日志文件单独执行一次。
copytruncate配置说明见文档
3. 手动测试轮转
# 调试模式 -d 参数表示进行一次调试运行,不会实际修改任何文件,但会显示将要执行的操作。强烈建议调试一下,是否能达到预期效果。
sudo logrotate -d /etc/logrotate.d/nginx
# 强制执行一次轮转(按需)
sudo logrotate -vf /etc/logrotate.d/nginx
4. 查看轮转结果
ls -lh /usr/local/nginx/logs/
# 输出示例(未启用日期后缀):
# access.log (今天)
# access.log.1 (昨天)
# access.log.2.gz (前天,已压缩)
# 输出示例(启用日期后缀):
# access.log (今天20260103)
# access.log-20260102 (昨天)
# access.log-20260101.gz (前天,已压缩)
5. 自动化日志轮转
logrotate通常由系统的cron任务自动调用。确保/etc/cron.daily/logrotate文件存在并可执行,这样系统每天都会自动执行日志轮转。
/etc/cron.daily/logrotate
#!/bin/sh
/usr/sbin/logrotate -f /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
/usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0
/etc/logrotate.conf
# see "man logrotate" for details
# rotate log files weekly
weekly
# keep 4 weeks worth of backlogs
rotate 4
# create new (empty) log files after rotating old ones
create
# use date as a suffix of the rotated file
dateext
# uncomment this if you want your log files compressed
#compress
# RPM packages drop log rotation information into this directory
include /etc/logrotate.d
# no packages own wtmp and btmp -- we'll rotate them here
/var/log/wtmp {
monthly
create 0664 root utmp
minsize 1M
rotate 1
}
/var/log/btmp {
missingok
monthly
create 0600 root utmp
rotate 1
}
# system-specific logs may be also be configured here.
方法二:使用 cron + 脚本手动分割
如果不想使用 logrotate,可以写一个 cron 定时任务。
1. 创建分割脚本 /usr/local/bin/nginx-log-rotate.sh
#!/bin/bash
# Nginx 日志按天分割
LOGS_PATH=/usr/local/nginx/logs
YESTERDAY=$(date -d "yesterday" +%Y%m%d)
# 移动旧日志
mv ${LOGS_PATH}/access.log ${LOGS_PATH}/access_${YESTERDAY}.log
mv ${LOGS_PATH}/error.log ${LOGS_PATH}/error_${YESTERDAY}.log
# 重新打开日志文件
kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
# 可选:压缩并删除30天前的日志
find ${LOGS_PATH} -name "access_*.log" -mtime +30 -exec gzip {} \;
find ${LOGS_PATH} -name "error_*.log" -mtime +30 -exec gzip {} \;
2. 添加执行权限
chmod +x /usr/local/bin/nginx-log-rotate.sh
3. 添加 cron 任务(每天 00:00 执行)
crontab -e
# 添加一行
0 0 * * * /usr/local/bin/nginx-log-rotate.sh
方法三:使用 Nginx 内置变量(仅适用于访问日志,有一定限制)
Nginx 的 access_log 指令支持变量,可以通过 $time_iso8601 等动态生成日志文件名,实现“按天记录”。但这种方法有性能问题(每次请求都要解析变量并打开新文件),不推荐在高并发下使用。
http {
# 不建议在高并发下使用
map $time_iso8601 $logdate {
~^(?<ymd>\d{4}-\d{2}-\d{2}) $ymd;
default 'nodate';
}
access_log /usr/local/nginx/logs/access-$logdate.log main;
}
验证日志轮转是否生效
查看当前日志文件
ls -l /usr/local/nginx/logs
查看 logrotate 运行状态
cat /var/lib/logrotate/status | grep nginx
手动触发并观察
sudo logrotate -vf /etc/logrotate.d/nginx
# 观察日志文件变化
watch -n 1 'ls -lh /usr/local/nginx/logs/'
注意事项
- 权限问题:确保日志目录和文件权限正确,Nginx 进程用户(通常是
www-data或nginx)有写权限。 - 信号处理:重新打开日志的正确信号是
USR1,nginx -s reopen也能达到同样效果。在 logrotate 脚本中推荐使用kill -USR1。 - 日志格式:如果自定义了日志格式,
access_log指令中需要指定格式名称。 - 容器环境:如果运行在 Docker 中,建议将日志输出到 stdout/stderr,由容器运行时或日志驱动处理,而不是在容器内分割。
总结
- 最佳实践:使用系统自带的
logrotate,配置简单且稳定。 - 备选方案:cron 脚本。
- 不推荐:Nginx 变量动态文件名(高并发下性能差)。
3050

被折叠的 条评论
为什么被折叠?



