对网上几篇写的不错的nginx日志切割文档进行梳理:

(一)

nginx使用 logrotate 切割日志


大体上有三种方法切割nginx日志。

第一种是写个定时任务,每天零点把旧的日志重命名,并对nginx进程发送USR1信号使其重新打开日志并写入。

第二种是能过管道的方式把新产生的日志写到另外一个日志文件里。

第三种是能过logrotate来切割日志,logrotate是系统自带的服务,可以切割任何日志,不仅仅是nginx,这里推荐使用它。

步骤1:

vi /etc/logrotate.d/nginx

文件内容如下

/usr/local/nginx/logs/access.log {     # 日志存放路径
daily                                  # 以天为单位切割
rotate 7                               # 轮询为7天,保留7天的记录
missingok                              # 如果日志不存在,不提示错误
notifempty                             # 如果日志为空,则不轮换
dateext                                # 轮换的日志后缀为-YYYYMMDD格式
sharedscripts 
postrotate 
    if [ -f /usr/local/nginx/logs/nginx.pid ]; then 
        kill -USR1 `cat /usr/local/nginx/logs/nginx.pid` 
    fi 
endscript 
}

步骤2:测试是否可用

/usr/sbin/logrotate -f /etc/logrotate.d/nginx

步骤3:配置定时任务

00 00 * * *  /usr/sbin/logrotate -f /etc/logrotate.d/nginx

完成!

(二)使用定时任务重命名切割日志

nginx 日志文件切割

连接地址:http://www.cnblogs.com/benio/archive/2010/10/13/1849935.html

Nginx 是一个非常轻量的 Web 服务器,体积小、性能高、速度快等诸多优点。但不足的是也存在缺点,比如其产生的访问日志文件一直就是一个,不会自动地进行切割,如果访问量很大的话,将 导致日志文件容量非常大,不便于管理。当然了,我们也不希望看到这么庞大的一个访问日志文件,那需要手动对这个文件进行切割。

在 Linux 平台上 Shell 脚本丰富,使用 Shell 脚本加 crontab 命令能非常方便地进行切割,但在 Windows 平台上就麻烦一些了,刚才弄了好长时间,就在这里记录整理一下。

日志文件切割要求

由于 Nginx 的日志都是写在一个文件当中的,因此,我们需要每天零点将前一天的日志存为另外一个文件,这里我们就将 Nginx 位于 logs 目录中的 access.log 存为 access_[yyyy-MM-dd].log 的文件。其实 logs 目录中还有个 error.log 的错误日志文件,这个文件也需要每天切割一个,在这里就说 access.log 了,error.log 的切割方法类似。

Linux 平台切割

在 Linux 平台上进行切割,需要使用 date 命令以获得昨天的日期、使用 kill 命令向 Nginx 进程发送重新打开日志文件的信号,以及 crontab 设置执行任务周期。

先创建一个 Shell 脚本,如下:

Shell代码 

  1. #!/bin/bash

  2. ## 零点执行该脚本


  3. ## Nginx 日志文件所在的目录

  4. LOGS_PATH=/usr/local/nginx/logs


  5. ## 获取昨天的 yyyy-MM-dd

  6. YESTERDAY=$(date -d ”yesterday” +%Y-%m-%d)


  7. ## 移动文件

  8. mv ${LOGS_PATH}/access.log ${LOGS_PATH}/access_${YESTERDAY}.log


  9. ## 向 Nginx 主进程发送 USR1 信号。USR1 信号是重新打开日志文件

  10. kill -USR1 $(cat /usr/local/nginx/nginx.pid)

#!/bin/bash
## 零点执行该脚本
## Nginx 日志文件所在的目录
LOGS_PATH=/usr/local/nginx/logs
## 获取昨天的 yyyy-MM-dd
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
## 移动文件
mv ${LOGS_PATH}/access.log ${LOGS_PATH}/access_${YESTERDAY}.log
## 向 Nginx 主进程发送 USR1 信号。USR1 信号是重新打开日志文件
kill -USR1 $(cat /usr/local/nginx/nginx.pid)

上面这个脚本中的最后一行必须向 Nginx 的进程发送 USR1 信号以重新打开日志文件,如果不写的话,Nginx 会继续将日志信息写入 access_[yyyy-MM-dd].log 的那个文件中,这显然是不正确的。

脚本完成后将其存入 Nginx 安装目录的 sbin 中,取名为 cut-log.sh,之后使用 crontab -e 新增一个定时任务,在其中增加执行这个脚本:

Shell代码 

  1. 0 0 * * * /bin/bash /usr/local/nginx/sbin/cut-log.sh

0 0 * * * /bin/bash /usr/local/nginx/sbin/cut-log.sh

到这里 Linux 下切割 Nginx 日志就完成了,可以将 crontab 设置为距当前时较近的时间测试一下,否则在零点出问题就不好了 。

Windows 平台切割

要在 Windows 平台上做这件事情就有点麻烦了。在 Windows 中没有原生的命令能够获得昨天的日期,Windows 中的计划任务设置我感觉也没有 Linux 的 crontab 用得方便,再有批处理命令也没有 Shell 脚本功能强大。总之,逐一来解决这些问题吧。

新浪博客上有一篇文章 nginx for windows日志切割,但这篇文章有两个不足之处:切割后的日志文件不是以昨天的日期命名;需要停止 Nginx 服务。为了切割日志停止服务,我认为有所不值,如果访问量较小的话问题不大,但是访问量较大的话这种做法是非常不可取的。为了弥补这些缺陷,我们对这个批处理文件进行了改进。

要 Windows 平台上使用 Linux 的 date 命令以获得昨天的日期,我们可以到 SourceForge上去下载 UnxUtils这 个工具。UnxUtils 是个非常强大的工具集,将大多数的 Linux 命令都移植到 Windows 平台上来了,比如:ls, grep, wc 等等 120 个命令,当然了其中也包括了我们需要的 date 工具。将这个工具解压到一个目录中,假定是 d:\common-path\UnxUtils 目录中,将那些工具所在的 d:\common-path\UnxUtils\usr\local\wbin 添加到系统的环境变量 PATH 中,可以加到最后去。由于 Windows 平台中有 date 内置命令,因此需要将 UnxUtils 的 date.exe 改名为其他的,比如改为 udate.exe。用 cmd 打开控制台,输入:

D:\>udate -d "yesterday" +%Y-%m-%d
2010-05-31
D:\>_

如果能正确输出昨天日期的话,那么这一点我们就搞定了 。

接下来需要写一个批处理文件,假定我们的 Nginx 是放在 d:\httpServer\nginx-0.7.64 目录中的,我们就在这个目录中建一个 cut-log.bat 的文件:

Batch代码 

  1. @echo off


  2. rem  获取昨天的日期,存入 YESTERDAY 变量,udate 参数中的 % 需要改成 %% 进行转义

  3. for /f %%a in (‘udate -d ”yesterday” +%%Y-%%m-%%d’) do set YESTERDAY=%%a


  4. rem 设置 Nginx 位于的盘符

  5. set NGINX_DRIVER=d:


  6. rem 设置 Nginx 的主目录

  7. set NGINX_PATH=%NGINX_DRIVER%\green\httpServer\nginx-0.7.64


  8. rem 设置 Nginx 的日志目录

  9. set LOG_PATH=%NGINX_PATH%\logs


  10. rem 移动文件

  11. move %LOG_PATH%\access.log %LOG_PATH%\access_%YESTERDAY%.log


  12. rem 切换到 Nginx 所在的盘符

  13. %NGINX_DRIVER%


  14. rem 进入 Nginx 的主目录

  15. cd %NGINX_PATH%


  16. rem 向 nginx 发送 reopen 信号以重新打开日志文件,功能与 Linux 平台中的 kill -USR1 一致

  17. nginx -s reopen

  18. echo on

@echo off
rem  获取昨天的日期,存入 YESTERDAY 变量,udate 参数中的 % 需要改成 %% 进行转义
for /f %%a in ('udate -d "yesterday" +%%Y-%%m-%%d') do set YESTERDAY=%%a
rem 设置 Nginx 位于的盘符
set NGINX_DRIVER=d:
rem 设置 Nginx 的主目录
set NGINX_PATH=%NGINX_DRIVER%\green\httpServer\nginx-0.7.64
rem 设置 Nginx 的日志目录
set LOG_PATH=%NGINX_PATH%\logs
rem 移动文件
move %LOG_PATH%\access.log %LOG_PATH%\access_%YESTERDAY%.log
rem 切换到 Nginx 所在的盘符
%NGINX_DRIVER%
rem 进入 Nginx 的主目录
cd %NGINX_PATH%
rem 向 nginx 发送 reopen 信号以重新打开日志文件,功能与 Linux 平台中的 kill -USR1 一致
nginx -s reopen
echo on

这个批处理写好后,将其加入 Windows 的计划任务中,设置为每天零时执行。需要注意的是,在执行 nginx -s reopen 命令时,当前目录必须位于 Nginx 的主目录中,否则会找不到日志文件在哪个目录中(估计 Nginx 默认采用相对路径寻找),这也就是批处理中需要进入盘符和 Nginx 主目录的原因了,因为任务计划执行时并不是在 Nginx 的主目录中。

结束语

这里主要介绍了一下 Linux 平台和 Windows 平台上切割 Nginx 日志文件的方法。Linux 中可以直接使用一些内置的命令完成,而在 Windows 中需要装载 UnxUtils 工具,不过这个工具集非常有用,比如使用其中的 tail 命令,我们在 Windows 中也能很方便地在控制台中使用 tail -f 实时地查看日志文件的输出。


(三)

nginx自动切割访问日志

 

Web 访问日志 (access_log) 记录了所有外部客户端对Web服务器的访问行为,包含了客户端IP,访问日期,访问的URL资源,服务器返回的HTTP状态码等重要信息。
一条典型的Web访问日志如下:


112.97.37.90 - - [14/Sep/2013:14:37:39 +0800] "GET / HTTP/1.1" 301 5 "-" "Mozilla/5.0 (Linux; U; Android 2.3.6; zh-cn; Lenovo A326 Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MicroMessenger/4.5.1.259" -

 

规划:

1、  要解决问题:

当网站访问量大后,日志数据就会很多,如果全部写到一个日志文件中去,文件会变得越来越大。文件大速度就会慢下来,比如一个文件几百兆。写入日志的时候,会影响操作速度。另外,如果我想看看访问日志,一个几百兆的文件,下载下来打开也很慢。使用第三方免费的日志分析工具-日志宝,可以上传nginx、apache、iis的日志文件,它们帮助分析网站安全方面。毕竟专攻,更加专业。日志宝对上传的文件也是做了大小限制的,不超过50m。

 

2、nignx没有自动分开文件存储日志的机制。由于nginx它不会帮你自动分文件保存。所以,需要自己编写脚本来实现。

 

shell脚本文件nginx_log_division.sh内容如下:

 

# /bin/bash

logs_path="/data/wwwlogs/"

#以前的日志文件。

log_name="xxx.log"   

pid_path="/usr/local/nginx/logs/nginx.pid"

 

mv ${logs_path}${log_name} ${logs_path}${log_name}_$(date --date="LAST   WEEK" +"%Y-%m-d").log

 

kill -USR1 `cat ${pid_path}`

 

上面shell脚本的原理是:先把以前的日志文件移动重命名成一个,目的是就是备份。

按照上个周一的本日来命名,运行脚本的时候时间点是”2013-09-16”,那么生成文件名称是”xxx.log_ 20130909.log”。

在没有执行kill -USR1 `cat ${pid_path}`之前,即便已经对文件执行了mv命令而改变了文件名称,nginx还是会向新命名的文件” xxx.log_ 20130909”照常写入日志数据的。原因在于:linux系统中,内核是根据文件描述符来找文件的。

 

----------------对linux文件描述符的理解

 

文件描述符是linux内核为每个打开的文件命名的一个整数标识。

linux内核为每一个进程生成(或者说维护)一个”文件描述符表”,这个文件描述符表记录的是“此进程所打开的文件(进行标识)”。

在这里的环境中,nginx就是一个运行中的进程,这个进程早就打开了一个日志文件,在文件描述符表是记录了文件的。

即便日志文件的路径改变了,但是还是能够找到(根据文件描述符表可以定位)。

 ----------------------------------------------

当执行命令“kill -USR1 `cat ${pid_path}`”的时候,nginx.pid文件中保存的其实就是一个数字(自己可以打开看一下,我这里是894),nginx 将其主进程的 pid (进程号)写入到了nginx.pid 文件中,所以可以通过cat命令直接拿到其主进程号,直接操作指定的进程号。

 

kill  -USR1 `cat ${pid_path}` 就等同于

kill –USR1 894  #指定发信号(USR1)信号给这个进程编号。

 

在linux系统中,linux是通过信号与”正在运行的进程”进行通信的。linux系统中,也很多预定义好的信号,像SIGHUP。USR1是用户自定义信号。可以理解为:进程自己定义接到这个信号该干嘛(也就是进程编写者自己确定收到这个信号干嘛还是什么都不做都行,完全交给开发人员自己决定)。而在nginx中,它自己编写了代码处理当我接到USR1信号的时候,让nginx重新打开日志文件。具体原理如下:

1、nginx 的主进程收到USR1信号,会重新打开日志文件(以nginx配置文件中的日志名称命名,就是配置文件中access_log项所设置的值,如果文件不存在,会自动创建一个新的文件xxx.log)。

 

2、然后把日志文件的拥有者改为“工作进程(worker进程)”,目的是让worker进程就具备了对日志文件的读写权限(master和worker通常以不同用户运行,所以需要改变拥有者)。

 

3、nginx主进程会关闭重名的日志文件(也就是刚才使用mv命令重命名成xxx.log_ 20130909.log的文件),并通知工作进程使用新打开的日志文件(刚才主进程打开的文件xxx.log)。具体实现上更细化点就是,主进程把USR1信号发给worker,worker接到这个信号后,会重新打开日志文件(也就是配置文件中约定的xxx.log)

  ===================================定时执行脚本

 设置上面的shell脚本文件加入到定时任务中去。crontab是linux下面一个定时任务进程。开机此进程会启动,它每隔一定时间会去自己的列表中看是否有需要执行的任务。

 

crontab  -e

* 04 * * 1 /data/wwwlogs/nginx_log_division.sh

  

会打开一个文件,加入上面的代码

格式为 "分 时 日 月 星期几  要执行的shell文件路径"。用*可以理解成“每”,每分钟,每个小时,每个月等等。

我设置是在周一凌晨4点运行nginx_log_division.sh脚本,脚本的内容就是重新生成一个新的日志文件。

  

附:设置nginx日志的配置方法

 

log_format  site  '$remote_addr - $remote_user [$time_local] "$request" '

             '$status $body_bytes_sent "$http_referer" '

             '"$http_user_agent" $http_x_forwarded_for';

 

access_log  /data/wwwlogs/xxxx.com.log  site

#第二个参数表示使用那个日志格式,为每一个日志格式标识了一个名称,site对应的就是log_format中的名称 

以上涉及到crontab定时任务管理器的使用知识。


linux中logrotate对日志进行切割压缩(nginx,mysql)

http://www.111cn.net/sys/linux/61133.htm