在linux上logrotate是一个日志文件管理工具。用于分割日志文件,删除旧的日志文件,并创建新的日志文件,起到“转储”作用,它是默认随linux一起被安装的。

1、logrotate基本介绍:

Logrotate是基于CRON来运行的,其脚本是/etc/cron.daily/logrotate,内容如下:

[root@huanqiu_web1 ~]# cat /etc/cron.daily/logrotate
#!/bin/sh

/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

1)日志轮询周期有这几种:

daily、weekly、monthly、yearly

默认是daily(即logrotate脚本放到了/etc/cron.daily下),具体执行时间可以查看 /etc/crontab 或者 /etc/anacrontab (CentOS)。

2)手动执行:

如果等不及cron自动执行日志轮转,想手动强制切割日志,需要加-f参数;

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

不过正式执行前最好通过Debug选项来验证一下(-d参数),这对调试也很重要

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

3)logrotate命令格式:

logrotate [OPTION...] <configfile>
-d, --debug :debug模式,测试配置文件是否有错误,不真实执行。
-f, --force :强制转储文件。
-m, --mail=command :压缩日志后,发送日志到指定邮箱。
-s, --state=statefile :使用指定的状态文件。
-v, --verbose :显示转储过程。

在 CentOS 中,默认会将日志保存 /var/lib/logrotate.status 文件中,如果需要指定到其它文件,可以通过 -s/--state 参数指定。

4)logrotate配置:

默认使用 /etc/logrotate.conf 文件,作为全局配置,而不同应用的具体配置则在 /etc/logrotate.d 目录下,通常以应用程序的名称命名,例如 nginx、mysql、syslog、yum 等配置。

例如:

/var/log/nginx/*.log /var/log/tomcat/*log {   # 可以指定多个路径
daily # 日志轮询周期,weekly,monthly,yearly
rotate 30 # 保存30天数据,超过的则删除
size +100M # 超过100M时分割,单位K,M,G,优先级高于daily
compress # 切割后压缩,也可以为nocompress
delaycompress # 切割时对上次的日志文件进行压缩
dateext # 日志文件切割时添加日期后缀
missingok # 如果没有日志文件也不报错
notifempty # 日志为空时不进行切换,默认为ifempty
create 640 nginx nginx # 使用该模式创建日志文件
sharedscripts # 所有的文件切割之后只执行一次下面脚本
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}

当配置完成后,可以通过如下方式进行测试。

----- 可直接手动执行
$ logrotate --force /etc/logrotate.d/nginx
----- 显示详细的信息;而且--debug/-d实际上不会操作具体文件(Dry Run)
$ logrotate --debug --verbose --force /etc/logrotate.d/nginx

2、日志处理:

首先,介绍下在 Linux 系统中是如何处理文件的。

进程每打开一个文件,系统会分配一个新的文件描述符给这个文件;这个文件描述符中保存了文件的状态信息、当前文件位置以及文件的 inode 信息。对文件的操作是通过文件描述符完成,所以文件路径发生改变不会影响文件操作。

测试:

#!/bin/python
import time
with open("/tmp/foobar.txt", "w") as file:
while 1:
file.write("test\n")
file.flush()
time.sleep(1)

当通过 mv /tmp/foobar.txt /tmp/test.txt 移动文件之后,可以看到 test.txt 文件仍然在写入。原因如上所述,Linux 在执行 mv 操作时,文件描述符是不变的,只修改了文件名。

其中 logrotate 提供了两种方式,分别为 create 和 copytruncate 。

1)create:

这也就是默认的方案,可以通过 create 命令配置文件的权限和属组设置;这个方案的思路是重命名原日志文件,创建新的日志文件。详细步骤如下:

  1. 重命名正在输出日志文件,因为重命名只修改目录以及文件的名称,而进程操作文件使用的是 inode,所以并不影响原程序继续输出日志。
  2. 创建新的日志文件,文件名和原日志文件一样,注意,此时只是文件名称一样,而 inode 编号不同,原程序输出的日志还是往原日志文件输出。
  3. 最后通过某些方式通知程序,重新打开日志文件;由于重新打开日志文件会用到文件路径而非 inode 编号,所以打开的是新的日志文件。

如上也就是 logrotate 的默认操作方式,也就是 mv+create 执行完之后,通知应用重新在新文件写入即可。mv+create 成本都比较低,几乎是原子操作,如果应用支持重新打开日志文件,如 syslog, nginx, mysql 等,那么这是最好的方式。

不过,有些程序并不支持这种方式,压根没有提供重新打开日志的接口;而如果重启应用程序,必然会降低可用性,为此引入了如下方式。

2)copytruncate:

该方案是把正在输出的日志拷 (copy) 一份出来,再清空 (trucate) 原来的日志;详细步骤如下:

  1. 将当前正在输出的日志文件复制为目标文件,此时程序仍然将日志输出到原来文件中,此时,原文件名也没有变。
  2. 清空日志文件,原程序仍然还是输出到预案日志文件中,因为清空文件只把文件的内容删除了,而 inode 并没改变,后续日志的输出仍然写入该文件中。

如上所述,对于 copytruncate 也就是先复制一份文件,然后清空原有文件。

通常来说,清空操作比较快,但是如果日志文件太大,那么复制就会比较耗时,从而可能导致部分日志丢失。不过这种方式不需要应用程序的支持即可。

3、其他:

1)sharedscripts的作用是什么?
如上配置中,通过通配符 '*' 指定了多个日志文件,例如 access.log、error.log ,这时会在所有的日志文件都执行完成之后,再统一执行一次脚本;如果没有这条命令,则每个日志文件执行完成后都会执行一次脚本。

2)rotate和maxage的区别是什么?
都是用来控制保存多少日志文件的,区别在于 rotate 是以个数为单位的,而 maxage 是以天数为单位的。如果是以天来轮转日志,那么二者的差别就不大。