Logrotate总结
目录
运行机制(参考博客:https://www.cnblogs.com/sailrancho/p/4784763.html)... 1
运行原理(参考博客:https://www.cnblogs.com/sailrancho/p/4784763.html)... 2
Logrotate机制与原理
运行机制(参考博客:https://www.cnblogs.com/sailrancho/p/4784763.html)
logrotate在很多Linux发行版上都是默认安装的。系统会定时运行logrotate,一般是每天一次。系统是这么实现按天执行的?
logrotate是基于crond服务来运行的,crond服务加载/etc/cron.d/0hourly --->在每小时的01分执行/etc/cron.hourly/0anacron --->执行anacron --->根据/etc/anacrontab的配置执行/etc/cron.daily,/etc/cron.weekly,/etc/cron.monthly --->执行/etc/cron.daily/下的logrotate脚本 --->执行logrotate --->根据/etc/logrotate.conf配置执行脚本/etc/logrotate.d/nginx --->转储日志成功(标红字是关键步骤,自定义日志轮转的关键)
cron 服务详解应用说明:http://blog.chinaunix.net/uid-28794117-id-4338874.html
从上述流程来看,crontab会每天定时执行/etc/cron.daily目录下的脚本,而这个目录下有个文件叫logrotate。在centos上脚本内容是这样的:
/etc/cron.daily/logrotate
1 2 3 4 5 6 | /usr/sbin/logrotate /etc/logrotate.conf >/dev/null 2>&1 EXITVALUE=$? if [ $EXITVALUE != 0 ]; then /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]" fi exit 0 |
可以看到这个脚本主要做的事就是以/etc/logrotate.conf为配置文件执行了logrotate。就是这样实现了每天执行一次logrotate。
如何自定义日志轮转呢?
1.可以把/etc/cron.daily/logrotate拷出来,改logrotate配置文件的路径,然后在crontab里加上一条指定时间执行这个脚本的记录,自定义周期滚动日志就大功告成了。这种自定义的方式有两点要注意:
- 配置文件里一定要配置rotate 文件数目这个参数。如果不配置默认是0个,也就是只允许存在一份日志,刚切分出来的日志会马上被删除。
- 执行logrotate命令最好加-f参数,不然有时候配置文件修改的内容不生效
2.可以再写一个脚本文件去执行logrotate,指定相应的logrotate.conf配置文件。
运行原理(参考博客:https://www.cnblogs.com/sailrancho/p/4784763.html)
logrotate是怎么做到滚动日志时不影响程序正常的日志输出呢?logrotate提供了两种解决方案
方案1:默认
这个方案的思路是重命名原日志文件,创建新的日志文件。详细步骤如下:
- 重命名程序当前正在输出日志的程序。因为重命名只会修改目录文件的内容,而进程操作文件靠的是inode编号,所以并不影响程序继续输出日志。
- 创建新的日志文件,文件名和原来日志文件一样。虽然新的日志文件和原来日志文件的名字一样,但是inode编号不一样,所以程序输出的日志还是往原日志文件输出。
- 通过某些方式通知程序,重新打开日志文件。程序重新打开日志文件,靠的是文件路径而不是inode编号,所以打开的是新的日志文件。
什么方式通知程序我重新打开日志呢,简单粗暴的方法是杀死进程重新打开。很多场景这种作法会影响在线的服务,于是有些程序提供了重新打开日志的接口,比如可以通过信号通知nginx。各种IPC方式都可以,前提是程序自身要支持这个功能。
有个地方值得一提,一个程序可能输出了多个需要滚动的日志文件。每滚动一个就通知程序重新打开所有日志文件不太划得来。有个sharedscripts的参数,让程序把所有日志都重命名了以后,只通知一次。
方案2:copytruncate
这个方案的思路是把正在输出的日志拷(copy)一份出来,再清空(trucate)原来的日志。详细步骤如下:
- 拷贝程序当前正在输出的日志文件,保存文件名为滚动结果文件名。这期间程序照常输出日志到原来的文件中,原来的文件名也没有变。
- 清空程序正在输出的日志文件。清空后程序输出的日志还是输出到这个日志文件中,因为清空文件只是把文件的内容删除了,文件的inode编号并没有发生变化,变化的是元信息中文件内容的信息。
结果上看,旧的日志内容存在滚动的文件里,新的日志输出到空的文件里。实现了日志的滚动。
这个方案有两个有趣的地方。
- 文件清空并不影响到输出日志的程序的文件表里的文件位置信息,因为各进程的文件表是独立的。那么文件清空后,程序输出的日志应该接着之前日志的偏移位置输出,这个位置之前会被\0填充才对。但实际上logroate清空日志文件后,程序输出的日志都是从文件开始处开始写的。这是怎么做到的?这个问题让我纠结了很久,直到某天灵光一闪,这不是logrotate做的,而是成熟的写日志的方式,都是用O_APPEND的方式写的。如果程序没有用O_APPEND方式打开日志文件,变会出现copytruncate后日志文件前面会被一堆\0填充的情况。
- 日志在拷贝完到清空文件这段时间内,程序输出的日志没有备份就清空了,这些日志不是丢了吗?是的,copytruncate有丢失部分日志内容的风险。所以能用create的方案就别用copytruncate。所以很多程序提供了通知我更新打开日志文件的功能来支持create方案,或者自己做了日志滚动,不依赖logrotate
配置文件 logrotate.conf
1.文件开始是需要加入轮转的日志的路径,如/mnt/sdacard/syslog/syslog
2.然后是用{}包起来的执行参数,一行一个。
上图中的样例的执行效果是:最多会存在50个文件;文件大小为10M;当日志文件为空时,不进行轮转;轮转方案选择:copytruncate(基于拷贝)
其他参数说明:
配置:
要求:按照日志大小切分,50个文件数量来轮转,即是四中的配置文件
如何触发去执行呢?根据需求,会一直调用logrotate,而不是定时的。
写一个脚本auto_logrotate来执行logrotate
只有日志文件大小达到设定的大小才需执行logrotate.故为了避免频繁调用logrotate,可以对大小有个判断再去执行
#!/bin/sh log_file=$1 conf_file=$2 size_threshold=$3
chmod 644 $conf_file chown root $conf_file chgrp root $conf_file
logrotate -f $conf_file
while [ $a -z ]; do sleep 1; size=`stat -c "%s" $log_file` if [ $size -ge $size_threshold ]; then logrotate $conf_file; fi done |
具体执行时候流程如下:
1.每执行一次logrotate,会先判断当前日志当syslog这个文件大小达到10M时,就会生成新的syslog进行存储。
2.当生成了第51个文件时,这个文件会被删除,只保留50个文件。
然后开始轮转。最终的状态是有51个文件。一个syslog 和50个syslog.1~syslog.50