什么是logrotate

logrotate是一款用来切割日志的工具,更确切的说,是切割文本的工具,但通常用在软件日志切割上。为什么要进行日志切割呢?原因可以有很多,最明显的一个就是防止日志文件变得太大。

lorotate的切割方式

以nginx为例,假设其错误日志放在/data/proclog/log/nginx/下,名为nginx_error.log,当logrotate运行时,如果满足切割要求了,则会将nginx_error.log改名为nginx_error.log.1,并重新创建一个新的空文件nginx_error.log作为新的错误日志。

当进行其二次切割时,nginx_error.log.1被改名为nginx_error.log.2,刚才创建的nginx_error.log被改名为新的nginx_error.log.1,然后再次重新创建一个新的空文件nginx_error.log作为新的错误日志投入使用。

当进行第三次切割时,nginx_error.log.2变为nginx_error.log.3,nginx_error.log.1变为nginx_error.log.2,nginx_error.log变为nginx_error.log.1,一个新的nginx_error.log被再次创建。

依次类推。

至于到底会保留多少份nginx_error.log.N(N代表数字),则是在logrotate的配置文件一个参数rotate设置的。例如,当rotate设置为3时,则只会保留nginx_error.log.1、nginx_error.log.2和nginx_error.log.3,老的文件会被删除。

logrotate与crond

logrotate默认会放在cron.daily目录下,每天自动运行。 执行:

vim /etc/cron.daily/logrotate  

看到该文件内容如下:

#!/bin/sh  
  
/usr/sbin/logrotate /etc/logrotate.conf  
EXITVALUE=$?  
if [ $EXITVALUE != 0 ]; then  
    /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"  
fi  

上面的shell脚本主要是执行/usr/sbin/logrotate程序,并检查执行状态,如果执行出错,则通过logger程序向系统日志中发送一条错误消息。

注意,现在说道的logrotate有两个,一个是shell脚本,位于/etc/cron.daily下,一个是可执行文件,位于/usr/sbin目录下。

继续看上面的logrotate脚本,其中错误处理语句中,logger程序是怎么运行的呢?我们可以做个小测试。 执行:

/usr/bin/logger -t strider "Good Morning"  

屏幕没有任何打印信息,但我们可以查看/var/log/message:

tail /var/log/messages  

观察最后一条信息:

Sep 10 06:53:55 localhost strider: Good Morning  

可见logrotate脚本的错误信息通过通过logger程序送到系统日志中去了。

/etc/cron.daily、/etc/crontab

上面我们说到,logrotate脚本放在/etc/cron.daily目录下,所以它会每天定期执行一次。为什么放在cron.daily目录下就会有此效果呢?而且,到底是在每天的什么时候执行呢?
linux下的定时任务是由系统服务crond来管理的。crond的配置文件是/etc/crontab,可以打开观察一下:

vim /etc/crontab  

会看到如下内容:

SHELL=/bin/bash  
PATH=/sbin:/bin:/usr/sbin:/usr/bin  
MAILTO=root  
HOME=/  
  
### run-parts  
01 * * * * root run-parts /etc/cron.hourly  
02 4 * * * root run-parts /etc/cron.daily  
22 4 * * 0 root run-parts /etc/cron.weekly  
42 4 1 * * root run-parts /etc/cron.monthly  

其中,SHELL字段、PATH字段等内容不用多说,重点看下下面的字段。如果你用crontab -e指令来写过crontab定时任务的话,一定会觉得跟crontab中的格式一模一样。其实这是错觉,/etc/crontab的配置中,每一行都多了一个root,表示以什么用户来执行,而crontab -e配置中,则没有这一个用户名字段。

虽然有这一点区别,其他地方意义还是一样的,例如:

02 4 * * * root run-parts /etc/cron.daily  

就表明,每天凌晨的4:02时刻,以root身份执行run-parts /etc/cron.daily命令。我们大概也能猜出来了,run-parts的作用就是执行后面目录下的所有脚本,所以放在cron.daily目录下的脚本,会每天被执行一次。cron.hourly、cron.weekly、cron.monthly等也是如此。

run-parts

那么run-parts到底是怎么做的呢?我们可以确定一下,执行:

whereis run-parts  

输出:

run-parts: /usr/bin/run-parts  

查看run-parts类型,执行:

file /usr/bin/run-parts  

输出:

/usr/bin/run-parts: Bourne-Again shell script text executable  

可见run-parts是一个bash脚本,其内容及注释如下:

#!/bin/bash  
  
# run-parts - concept taken from Debian  
  
# keep going when something fails  
#当shell中某些命令或子shell执行错误时,该脚本让然能够执行下去。  
set +e  
  
#如果参数小于1,则打印用法信息,并退出  
if [ $# -lt 1 ]; then  
        echo "Usage: run-parts <dir>"  
        exit 1  
fi  
  
#如果所带参数不是一个目录,则报错,并退出  
if [ ! -d $1 ]; then  
        echo "Not a directory: $1"  
        exit 1  
fi  
  
# Ignore *~ and *, scripts  
#忽略该目录下,文件名中带有~和,的脚本  
for i in $1/*[^~,] ; do  
        #忽略子目录  
        [ -d $i ] && continue  
  
        #忽略rpmsave、rpmorig、rpmnew、swp、v格式的文件  
        # Don't run *.{rpmsave,rpmorig,rpmnew,swp} scripts  
        [ "${i%.rpmsave}" != "${i}" ] && continue  
        [ "${i%.rpmorig}" != "${i}" ] && continue  
        [ "${i%.rpmnew}" != "${i}" ] && continue  
        [ "${i%.swp}" != "${i}" ] && continue  
        [ "${i%,v}" != "${i}" ] && continue  
  
        #如果该文件可执行,则执行之  
        if [ -x $i ]; then  
                $i 2>&1 | awk -v "progname=$i" \  
                              'progname {  
                                   print progname ":\n"  
                                   progname="";  
                               }  
                               { print; }'  
        fi  
done  
  
exit 0  

/etc/crontab和crontab -e

与前面所说的logrotate一样,也有两个都叫crontab的文件,一个是/etc/crontab,是crond的配置文件,另一个是一个程序,是用户与crond交互的外部接口。

一面已经提到,/etc/crontab与 crontab的配置格式是不一样的,例如:

/etc/crontab中:

...(略)  
02 4 * * * root run-parts /etc/cron.daily  

与程序crontab对比一下,执行crontab -u root -l,可得到:

* * * * * /home/strider/project/worker/fdfs-v4.07/script/fdfs_worker_demeon.sh  
* * * * * /bin/bash /home/strider/project/worker/fdfs-v4.07/script/fdfs_add_task.sh 

可见,通过crontab程序设置crond时,是不需要添加用户的。原因很简单,crontab必须在执行时指定用户名(如果不指定,则默认为当前登录的用户),执行crontab -u username -e设置完规则后,这些规则会保存在/var/spool/cron/username文件中,每个用户的crontab配置都会保存在属于该用户的文件中。例如:

vim /var/spool/cron/root  

输出:

* * * * * /home/strider/project/worker/fdfs-v4.07/script/fdfs_worker_demeon.sh  
* * * * * /bin/bash /home/strider/project/worker/fdfs-v4.07/script/fdfs_add_task.sh 

与cront -u root -l回显一致。