跳转到内容

nginx日志切分

Nginx Log Rotation日志正确切分与定期删除
一般场景:Nginx Log Rotation日志需要定期进行切分,操作,再定期删除。

简单的说就是: mv 没有改变源文件的任何内容以及 inode 属性,也没有创建新文件,这样也就没有中断 nginx 进程对日志文件的读写,自然就不会有丢数据的风险了。而 cp 的话,是新建了一个目标空文件,然后去往里拷贝数据,这是需要时间的,而且无法保证对一个正在读写的文件拷贝数据的完整性。当你重定向清空源文件的时候,数据就会不同程度的丢失了。所以这里用 mv 而不是 cp,至此我想你也应当明白 cpmv 的区别了。

Terminal window
mv access.log access.log.0
kill -USR1 `cat master.nginx.pid`
sleep 1
gzip access.log.0 # do something with access.log.0
  1. 首先我们不是 cp,而是 mv 当前日志成为一个归档文件(最好加上时间后缀),此时文件 access.log 的 inode 并未改变,对于 Linux 进程来说,mv 并没有使文件发生变化,而进程是按 inode 追踪文件的,而不是文件名。所以直到 mv 完成以及 mv 完成后, nginx 进程会一直继续读写 access.log.0 文件(其实是 access.log,不是吗?)。

  2. Nginx 内部定义了 USR1 信号,这个信号和我们所用的 kill -9 信号类似的地方在于,他们都属于 linux 信号的一种,你可以 kill -l 查看全部信号的定义,各个发行版的定义会有些许差异;不同的地方在于,-9 属于系统级别的,而 USR1 属于应用软件级别的,开发者自定义的,至于程序收到 -USR1 信号后会干什么事,开发者自己说了算,这点和 -9 这种系统级别的信号不同。所以在这里,kill -USR1 不会杀死 Nginx 进程,而 Nginx Master 进程收到 -USR1 信号后,会重新打开名为 access.log 的日志文件,由于 access.log 已经不存在了,那么 access.log 会重新建立一个这样的文件,并开始往里读写数据,也就是说读写从 access.log.0 又切回到 access.log 了,这样新的请求日志会被重新开始记录了,而这个过程是没有任何读写中断,数据丢失的。

  3. 这句的意思是给一定的时间让上一步的读写切换顺利完成,以便可以进行后续的操作,对归档日志进行处理。比如有可能数据还在 nginx 的 buffer 中,没有及时写入 access.log.0 或是系统负载、IO 很高,没有及时响应切换,此时若强行对归档日志 access.log.0 进行处理,则会有数据丢失的风险。

  4. 这句代码就是用户后续对归档日志 access.log.0 进行处理了,你可以 gziprsync 等等,随你怎么玩吧。这里算是有了一个简单、完美的解决方案,其实你也可以用一些三方的工具来做 log rotation,比如 logrotate

示例:定时切分日志并定期删除

Section titled “示例:定时切分日志并定期删除”

编辑 /home/crontab/cut_nginx_log.sh 文件:

#!/bin/sh
logs_path="/usr/local/nginx/logs/"
DAYS=30
mv ${logs_path}bbs_access.log ${logs_path}nginx_logs/bbs_logs/bbs_access_$(date -d "yesterday" +"%Y%m%d").log
mv ${logs_path}sns_access.log ${logs_path}nginx_logs/sns_logs/sns_access_$(date -d "yesterday" +"%Y%m%d").log
kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
find ${logs_path}nginx_logs/bbs_logs/ -name "bbs_access_*" -type f -mtime +$DAYS -exec rm {} \;
find ${logs_path}nginx_logs/sns_logs/ -name "sns_access_*" -type f -mtime +$DAYS -exec rm {} \;

保存并退出:

Terminal window
:wq! #保存退出
chmod +x /home/crontab/cut_nginx_log.sh #添加脚本执行权限

修改 /etc/crontab 文件,在最后一行添加:

Terminal window
0 0 * * * root /home/crontab/cut_nginx_log.sh #表示每天凌晨执行
:wq! #保存退出

至此,Linux下定时切割Nginx访问日志并删除指定天数前的日志记录完成。

如果脚本在执行过程中出现下面错误:

Terminal window
nginx: open() "/usr/local/nginx/logs/nginx.pid" failed

解决办法:

Terminal window
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf

使用 nginx -c 的参数指定 nginx.conf 文件的位置