天天看点

Openresty学习使用(四)日志切割

Openresty学习使用(四)日志切割

    • 说明
    • Logrotate
    • 日志切割
    • 问题
      • 执行时间的问题
      • 如何告诉应用程序重新打开日志文件

说明

安装新版nginx的时候,会自动在/etc/logrotate.d目录下面生成一个nginx的文件,每天会自动进行日志切割,保留10天的文件等。但是openresty并没有这个功能,所以需要手动创建配置文件。

Logrotate

Linux服务器上我们可以用Logrotate来分割归档日志文件,结合crond我们可以指定每天在某个时间自动整理日志等文档,避免自己去编写复杂的crontab脚本。

Logrotate的配置文件位于 /etc/logrotate.conf,

Logrotate的子配置文件位于文件夹 /etc/logrotate.d/ 下。

常用命令

常用命令 描述
logrotate -d -v /etc/logrotate.d/nginx 测试指定的logrotate配置
logrotate /etc/logrotate.conf 重新读取配置文件,并对符合条件的文件文件进行rotate

logrotate主要参数如下表:

配置参数 功能说明
compress 通过gzip 压缩日志文件的所有非当前版本
nocompress 不需要压缩时,用这个参数
copytruncate 用于还在打开中的日志文件,把当前日志备份并截断
nocopytruncate 备份日志文件但是不截断
create mode owner group 转储文件,使用指定的文件模式创建新的日志文件
nocreate 不建立新的日志文件
delaycompress 和 compress 一起使用时,压缩所有版本,除了当前和下一个最近的
nodelaycompress delaycompress 选项,转储同时压缩。
errors address 专储时的错误信息发送到指定的Email 地址
ifempty 即使是空文件也转储,这个是 logrotate 的缺省选项。
notifempty 如果是空文件的话,不转储
dateext 定义日志文件后缀是日期格式,也就是切割后文件是:xxx.log-20160402.gz这样的格式。如果该参数被注释掉,切割出来是按数字递增,即前面说的 xxx.log-1这种格式
mail address 把转储的日志文件发送到指定的E-mail 地址
nomail 转储时不发送日志文件
olddir directory 转储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统
noolddir 转储后的日志文件和当前日志文件放在同一个目录下
prerotate/endscript 在转储以前需要执行的命令可以放入这个对,这两个关键字必须单独成行
postrotate/endscript 在转储以后需要执行的命令可以放入这个对,这两个关键字必须单独成行
daily 指定转储周期为每天
weekly 指定转储周期为每周
monthly 指定转储周期为每月
rotate 指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份
tabootext [+] list 让logrotate不转储指定扩展名的文件,缺省的扩展名是:.rpm-orig, .rpmsave, v, 和 ~
sharedscripts 对于整个日志组只运行一次脚本
size size当日志文件到达指定的大小时才转储,Size 可以指定 bytes (缺省)以及KB (sizek)或者MB (sizem).

日志切割

我们在/etc/logrotate.d下面新建openresty文件

/usr/local/openresty/nginx/logs/*log {
    daily
    missingok
    rotate 7
    notifempty
    sharedscripts
    compress
    delaycompress
    dateext
    postrotate
        [ ! -f /usr/local/openresty/nginx/logs/nginx.pid ] || kill -USR1 `cat /usr/local/openresty/nginx/logs/nginx.pid`
    endscript
}
           

执行logrotate /etc/logrotate.conf

需要说明的是sharedscripts,我在前面Nginx的例子里声明日志文件的时候用了星号通配符,也就是说这里可能涉及多个日志文件,比如:access.log和error.log。sharedscripts的作用是在所有的日志文件都轮转完毕后统一执行一次脚本。如果没有配置这条指令,那么每个日志文件轮转完毕后都会执行一次脚本。

问题

执行时间的问题

Logrotate是基于CRON运行的,所以这个时间是由CRON控制的。如果使用的是新版CentOS,那么配置文件为:/etc/anacrontab。

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22

#period in days   delay in minutes   job-identifier   command
1	5	cron.daily		nice run-parts /etc/cron.daily
7	25	cron.weekly		nice run-parts /etc/cron.weekly
@monthly 45	cron.monthly		nice run-parts /etc/cron.monthly
           

RANDOM_DELAY 指的是最大的延迟时间,这个时间被加在delay in minutes中,为最后生效的delay分钟数,也就是说每次执行日常任务是总是有一个随机5-50分钟的延时。

START_HOURS_RANGE 指定任务开始的小时数。

cron与anacron对比

Openresty学习使用(四)日志切割

所以如果你想在指定时间点,让logrotate切割日志的话,是不合适的。我们目前的场景是走了日志收集,所以啥时候切割并不是很重要。

如果想在指定时间点进行切割的话,参考如下脚本,然后配置crontab进行执行

#!/bin/bash
#初始化
LOGS_PATH=/usr/local/openresty/nginx/logs/
YESTERDAY=$(date -d "yesterday" +%Y%m%d)

#按天切割日志
mv ${LOGS_PATH}/access.log ${LOGS_PATH}/access_${YESTERDAY}.log

#向nginx主进程发送USR1信号,重新打开日志文件,否则会继续往mv后的文件写数据的。原因在于:linux系统中,内核是根据文件描述符来找文件的。如果不这样操作导致日志切割失败。

kill -USR1 `ps axu | grep "nginx: master process" | grep -v grep | awk '{print $2}'`

#删除7天前的日志
cd ${LOGS_PATH}
find . -mtime +7 -name "*20[1-9][3-9]*" | xargs rm -f
exit 0
           

如何告诉应用程序重新打开日志文件

以Nginx为例,是通过postrotate指令发送USR1信号来通知Nginx重新打开日志文件的。但是其他的应用程序不一定遵循这样的约定,比如说MySQL是通过flush-logs来重新打开日志文件的。更有甚者,有些应用程序就压根没有提供类似的方法,此时如果想重新打开日志文件,就必须重启服务,但为了高可用性,这往往不能接受。Logrotate提供了一个名为copytruncate的指令,此方法采用的是先拷贝再清空的方式,整个过程中日志文件的操作句柄没有发生改变,所以不需要通知应用程序重新打开日志文件,但是需要注意的是,在拷贝和清空之间有一个时间差,所以可能会丢失部分日志数据。

继续阅读