前言
在使用linux的过程中,我们常常需要查询一些日志。但是如果某个日志文件过于庞大,包含了跨度时间很长的日志内容,那么我们的查询过程就会比较麻烦,好似大海捞针。
好在linux给我们提供了一种功能,可以将目标日志进行切割和分散,由此就使得查询到目标内容更加容易。
而最常用的一个linux工具,叫做logrotate,本文主要讲解此工具的用法。
logrotate
1 安装
# For Ubuntu/Debian
apt update & apt install -y logrotate
# For CentOS
yum update & yum install -y logrorate
# logrotate path
whereis logrotate
2 配置文件
默认的配置文件为:/etc/logrotate.conf, 默认包含以下内容(具体配置项内容过多,故略去部分):
# see "man logrotate" for details
# rotate log files weekly 切割时间间隔
weekly
# keep 4 weeks worth of backlogs 保留日志时间
rotate 4
# create new (empty) log files after rotating old ones 切割后如何处理新文件
create
# use date as a suffix of the rotated file 文件命名规则
dateext
# uncomment this if you want your log files compressed 是否压缩文件
#compress
# RPM packages drop log rotation information into this directory 处理RPM包主导的应用日志处理,比如Apache, nginx等
include /etc/logrotate.d
# no packages own wtmp and btmp -- we'll rotate them here 处理非RPM包主导的应用日志处理,例如系统日志
/var/log/wtmp {
···
}
/var/log/btmp {
···
}
# system-specific logs may be also be configured here.
3 定时运行
面对服务器,我们不可能每一次都手动去跑logrotate,因此它需要配合定时器(crontab)来跑。
好在linux提供了crontab的脚本:/etc/cron.daily/logrotate,每天运行一次。
[root@node1 logrotate.d]# cat /etc/cron.daily/logrotate
#!/bin/sh
/usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
/usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0
4 添加配置项
上面的内容都是系统自动安排的,我们也没什么必要去做改变,但如果说我们需要对一个新的应用进行日志切割,我们在安装完之后,需要在配置项中做配置。
每安装一个包,它就会在include /etc/logrotate.d下添加一个配置项,我们可以直接在那里做配置(以nginx为例):
[root@node1 logrotate.d]# cat /etc/logrotate.d/nginx
/var/log/nginx/*.log {
create 0640 nginx root
daily
rotate 10
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
/bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
endscript
}
可以看到,它会规定相关的配置项,其中需要说明的是,postrotate需要给nginx的某个进程发送终止信号(USR1/USR2)后才可以重新启动一个log。
logrotate原理
logrotate属于热切割,即切割过程中并不影响正常的日志输出。
Linux文件操作机制
首先贴张介绍Linux的文件结构:
首先我们知道,目录也是文件,文件里存在两部分内容,一部分是inode索引,另一部分是文件内容。文件的inode可以查询文件本体的元数据,包括引用计数、操作权限、拥有者ID、创建时间、最后修改时间等。而文件名并不在元数据中,因此文件改名、移动,都不会改变文件,修改目录文件,也就是修改inode中的索引内容。
借《UNIX 环境高级编程》里的图说一下进程打开文件的机制。
进程每新打开一个文件,系统会分配一个新的文件描述符给这个文件。文件描述符对应着一个文件表。表里面存着文件的状态信息(O_APPEND
/O_CREAT
/O_DIRECT
…)、当前文件位置和文件的 inode 信息。系统会为每个进程创建独立的文件描述符和文件表,不同进程是不会共用同一个文件表。正因为如此,不同进程可以同时用不同的状态操作同一个文件的不同位置。文件表中存的是 inode 信息而不是文件路径,所以文件路径发生改变不会影响文件操作。
logrotate提供了两种方法去实现这种效果。
1. create(默认方案)
这个方案的思路是重命名原日志文件,并创建新的日志文件。具体步骤有三步:
1) 重命名正在输出的日志文件,因为重命名只改变目录及文件名称,而进程操作使用的是inode,所以并不影响原程序的输出。
2) 创建新的日志文件,保持文件名和原文件一致,但inode编号不同,故此文件初始为空。
3) 通过某些信号通知输出进程,重新打开日志文件。由于重新打开日志文件时只用到数据名并不用到inode,故新的日志会输出到步骤2创建的日志文件中,从而完成日志重定向。
好处:操作简单(mv+create),日志不会断
坏处:某些程序不提供重新打开日志文件的接口,而重启影响较大,故无法使用该方法。
2. copytruncate
这个方案的思路是将正在输出的日志拷贝一份出来,并清空原来的日志文件,使其重新写入。具体步骤有3步:
1) 将当前正在输出的日志copy一份出来,此时程序仍在写入原文件,原文件名称也没变。
2) 清空原日志文件,程序仍然会将日志输出到原文件,从而形成日志切割。
好处:兼顾了某些没有重新打开日志文件缺口程序的日志切割。
坏处:如果日志文件很大,copy时间很久,那么可能丢日志。
使用
logrotate的命令格式如下:
[root@node1 ~]# logrotate -?
用法: logrotate [OPTION...] <configfile>
-d, --debug Don't do anything, just test (implies -v)
-f, --force Force file rotation
-m, --mail=command Command to send mail (instead of `/bin/mail')
-s, --state=statefile Path of state file
-v, --verbose Display messages during rotation
-l, --log=STRING Log file
--version Display version information
Help options:
-?, --help Show this help message
--usage Display brief usage message
可以看到,最常用的功能是指定某个配置文件来用,常用选项也是-f的强制指定, 和-v的详细输出。
例如,我要手动切割nginx的日志,可以使用一下命令:
/usr/sbin/logrotate -vf /etc/logrotate.d/nginx
或者结合crontab使用。
crontab -e
*/30 * * * * /usr/sbin/logrotate /etc/logrotate.d/rsyslog > /dev/null 2>&1 &
也就可以了。