

介绍两种日志轮替工具:apache httpd自带的rotatelogs工具和cronolog工具。
1、访问日志CustomLog
使用CustomLog指令指定访问日志记录的位置,可以在同一个host下多次使用该指令表示同一条日志记录到多个位置。语法格式为:
CustomLog file|pipe format|nickname [env=[!]environment-variable| expr=expression]
使用LogFormat可以指定日志记录的事项,例如是否要记录客户端IP地址,是否要记录请求方法等。使用LogFormat还可以定义日志分类(在httpd术语中称为nickname),例如common类、combined类、combinedio类。它支持非常弹性化的记录事项,具体的见官方手册LogFormat:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
<IfModule logio_module>
# You need to enable mod_logio.c to use %I and %O
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>
然后使用CustomLog指令就可以使用已经定义的日志类。例如:
CustomLog "logs/access_log" combined
当然使用LogFormat定义分类只是为了方便,CustomLog指令完全可以不使用nickname而是直接定义要记录的事项。例如:
CustomLog "logs/access_log" "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
如果提供CustomLog的第三个参数,即env或者expr,则表示满足条件的请求才会记录日志。例如,当请求的是gif文件时将独立记录该日志,而其他请求则记录在另一个日志中。
SetEnvIf Request_URI \.gif$ gif-image
CustomLog "gif-requests.log" common env=gif-image
CustomLog "nongif-requests.log" common env=!gif-image
通常来说,除了特殊需求,一般都只需使用LogFormat提供的各个事项即可。否则日志订制就是一件复杂的事情。
2、错误日志ErrorLog
错误日志的级别LogLevel:debug, info, notice, warn(默认), error, crit, alert, emerg。
错误日志的定义语法:
ErrorLog file-path|syslog[:[facility][:tag]]
如果使用syslog替换file-path,则表示采用系统自带的syslog日志工具,facility是记录syslog日志的设施类型。一般来说,不会采用这种方法记录日志。
如果采用file-path,则有两种方式:直接指定文件路径;前面使用管道,表示将输出的日志作为标准输入传递给管道后的日志处理程序,例如传递给apache自带的rotatelogs工具。例如:
ErrorLog "logs/error_log"
ErrorLog "|/usr/local/apache/bin/rotatelogs /var/log/error_log 86400" common
当然,对于ErrorLog来说,数据量并不会太多,一般直接使用文件记录即可。对于CustomLog,则可以考虑使用日志切割工具进行分割、轮替等行为。
错误日志的记录格式由ErrorLogFormat指令控制,例如以下是worker和event模式下错误日志的默认记录格式,其中各参数代表的意义见官方手册ErrorLogFormat。
ErrorLogFormat "[%{u}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
3、日志轮替工具之rotatelogs
首先说明rotatelogs工具,它是apache httpd提供的一个基于时间间隔、大小切分日志的简单工具。它在默认启动时不会立即创建日志文件,而是在有请求到达时才会创建。同理在轮替时也如此,如果到达了轮替的时间间隔,如果没有新请求到达,则暂时不会创建新的日志文件。如果使用"-f"选项,则在启动时,不管是否有没有请求,都立即创建日志文件。如果使用"-c"选项,则在每次轮替时无论是否有新请求到达,都创建新日志文件。
rotatelogs [ -l ] [ -f ] [ -t ] [ -v ] [ -e ] [ -c ] [ -n number-of-files ] logfile rotationtime|filesize(B|K|M|G)
rotatelogs是一个配合Apache管道日志功能使用的简单程序,该程序腄处理apache生成的日志自动截断重生,也就是说可以按照固定的时间固定的大小生成新的文件,其属于'apache2-utils'软件包。
rotatelogs is a simple program for use in conjunction with Apache's piped logfile feature. It supports rotation based on a time interval or maximum size of the log.
可以通过管道来处理apache的日志文件,如下:
CustomLog "|bin/rotatelogs /var/logs/logfile 86400" common
这将创建日志文件/var/logs/logfile.nnnn,一般是24小时,之后又会创建新的文件。
CustomLog "|bin/rotatelogs /var/logs/logfile 5M" common
当文件大小达到5m后将会对日志文件重建。
ErrorLog "|bin/rotatelogs /var/logs/errorlog.%Y-%m-%d-%H_%M_%S 5M"
以日期日间以结尾且大小为5m轮循错误日志文件。
这里以整理apache的日志为例,首先在httpd.conf里面增加下面一句:
CustomLog "|bin/rotatelogs /var/logs/logfile 86400" common
此配置会建立文件/var/logs/logfile.nnnn,其中的nnnn是名义上的日志启动时的系统时间 (此时间总是回卷时间的倍数,可以用于cron脚本的同步)。在回卷时间到达时(在此例中是24小时以后),会产生一个新的日志。
CustomLog "|bin/rotatelogs /var/logs/logfile 5M" common
此配置会在日志文件大小增长到5兆字节时回卷该日志。
概要
rotatelogs logfile [ rotationtime [ offset ]] | [ filesizeM ]
选项
logfile:它加上基准名就是日志文件名。如果logfile中包含'%',则它会被视为用于的strftime(3)的格式字串;否则,它会被自动加上以秒为单位的.nnnnnnnnnn后缀。这两种格式都表示新的日志开始使用的时间。
rotationtime:日志文件回卷的以秒为单位的间隔时间
offset:相对于UTC的时差的分钟数。如果省略,则假定为0,并使用UTC时间。比如要指定UTC时差为-8小时的地区的当地时间,则此参数应为-480。
filesizeM:指定回卷时以兆字节为单位的后缀字母M的文件大小,而不是指定回卷时间或时差。
注意:如果不设置480这个参数,导致日志记录时间和服务器时间相差8小时,原来是rotatelogs有一个offset参数,表示相对于UTC的时差分钟数,中国是第八时区,相差480分钟。86400是表示1天的秒数。
以下是一些时间方面的可选参数:
%A 星期名全称(本地的)
%a 3个字符的星期名(本地的)
%B 月份名的全称(本地的)
%b 3个字符的月份名(本地的)
%c 日期和时间(本地的)
%d 2位数的一个月中的日期数
%H 2位数的小时数(24小时制)
%I 2位数的小时数(12小时制)
%j 3位数的一年中的日期数
%M 2位数的分钟数
%m 2位数的月份数
%p am/pm 12小时制的上下午(本地的)
%S 2位数的秒数
%U 2位数的一年中的星期数(星期天为一周的第一天)
%W 2位数的一年中的星期数(星期一为一周的第一天)
%w 1位数的星期几(星期天为一周的第一天)
%X 时间 (本地的)
%x 日期 (本地的)
%Y 4位数的年份
%y 2位数的年份
%Z 时区名
%% 符号`%'本身
更多详细选项说明:
logfile:指定日志记录路径。可以加上一些修饰符,例如时间类的a.log_%Y.%m.%d将在a.log后追加年、月、日的后缀,如果没有给定任何后缀修饰,则自动加上".nnnnnnnn",表示创建时的时间点换算成距离1970-01-01 00:00:00的总秒数,也就是"date +%s",每次轮替时也会加上该后缀。如果使用相对路径,则相对于ServerRoot。
-n:使用数字作为后缀,且表示轮替的循环列表,例如"-n 3"表示一直在log.1、log.2、log.3这三个文件中记录,不会再创建任何新的日志文件。
rotationtime:指定轮替的时间间隔。将初始化为对应时间格式的起始值。例如,设置为3600时,将表示在每个小时的开头进行轮替,尽管当前时间点进入下一个小时可能只有5分钟,在5分钟之后也会进行一次轮替。
filesize:以大小方式轮替日志。
-l:使用本地时间计算时间间隔。默认使用的是UTC时间。
-f:强制立即打开日志文件。因为有些时候在启动httpd时,可能一小段时间内没有任何请求到达,因为没有日志需要记录,所以暂时不会创建日志文件。使用该选项可立即创建文件。
-t:截断日志而不再是轮替日志。这种情况下,不会再添加任何文件后缀。
-v:详细记录轮替或截断时的信息。
-e:将日志也输出到标准错误输出中。当日志还需要被其他工具处理时,该选项有用。
-c:每个时间间隔到了都创建新文件,尽管没有日志到达。而默认的情况下,在轮替时间间隔到达时,如果没有日志到达,将暂时不会创建日志,而是等待第一个请求到达后才创建。
关于更多的时间类修饰符,见下文。
注意,如果出现了轮替时文件名重复的情况,例如按照5M大小进行轮替,但文件名的格式为"a.log_%Y.%m.%d",如果同一天内出现了多次轮替,由于文件名相同,则会覆盖旧文件进行记录。另外,rotatelogs只能对日志文件名本身使用时间类修饰符,无法将其设置在目录上,否则启动httpd时会因为无法打开日志而报错。
示例:以下使用了日志管道"|",表示记录的日志传递给后面的程序(此处为rotatelogs)进行处理。每天轮替一次$ServerRoot/logs/mylog.nnnnnnnn,其中nnnnnnnn是当前时间换算成秒的数值。且在启动时不立即创建日志文件,轮替时也不立即创建新日志文件。
CustomLog "|/usr/local/apache/bin/rotatelogs logs/mylog 86400" common
按照文件大小轮替。
CustomLog "|bin/rotatelogs /var/log/logfile 5M" common
轮替错误日志,达到5M时就轮替。
ErrorLog "|bin/rotatelogs /var/log/errorlog.%Y-%m-%d-%H_%M_%S 5M"
截断日志而非轮替日志。
CustomLog "|bin/rotatelogs -t /var/log/logfile 86400" common
以下是日期类的修饰符,后面的cronolog工具也采用这同一套修饰符:
%:%字符
n:换行
t:水平制表符
时间类:
H:小时(00..23)
I:小时(01..12)
p:该locale下的AM或PM标识
M:分钟(00..59)
S:秒 (00..61, which allows for leap seconds)
X:该locale下时间表示符(e.g.: "15:12:47")
Z:时区。若时区不能确定,则无意义
日期类:
a:该locale下的工作日简名(e.g.: Sun..Sat)
A:该locale下的工作日全名(e.g.: Sunday .. Satur-ay)
b:该locale下的月份简称(e.g.: Jan .. Dec)
B:该locale下的月份全称(e.g.: January .. December)
c:该locale下的日期和时间(e.g.: "Sun Dec 15 14:12:47 GMT 1996")
d:当月中的天数 (01 .. 31)
j:当年中的天数 (001 .. 366)
m:月数 (01 .. 12)
U:当年中的星期数,以周日作为一周开始,其中第一周为首个含星期天的星期(00..53)
W:当年中的星期数,以星期一作为一周的开始,其中第一周为首个含星期天的星期(00..53)
w:工作日数(0 .. 6, 0表示星期天)
x:该locale下的日期表示(e.g. "13/04/97")
y:两位数的年份(00 .. 99)
Y:四位数的年份(1970 .. 2038)
4、日志轮替工具之cronolog
可以在epel源中下载,或者从其github上下载并安装。
# cronolog -h
usage: cronolog [OPTIONS] logfile-spec
-H NAME, --hardlink=NAME maintain a hard link from NAME to current log
-S NAME, --symlink=NAME maintain a symbolic link from NAME to current log
-P NAME, --prev-symlink=NAME maintain a symbolic link from NAME to previous log
-l NAME, --link=NAME same as -S/--symlink
-h, --help print this help, then exit
-p PERIOD, --period=PERIOD set the rotation period explicitly
-d DELAY, --delay=DELAY set the rotation period delay
-o, --once-only create single output log from template (not rotated)
-x FILE, --debug=FILE write debug messages to FILE( or to standard error if FILE is "-")
-a, --american American date formats
-e, --european European date formats (default)
-s, --start-time=TIME starting time
-z TZ, --time-zone=TZ use TZ for timezone
-V, --version print version number, then exit
这个工具的使用非常简单,但必须得搞懂它的轮替原理。以下面设置为例:
CustomLog "|/usr/local/sbin/cronolog logs/%Y/%m/%d/access.log" combined
由于使用的是相对路径,所以它相对于ServerRoot。假设ServerRoot为/usr/local/apache,则这里的日志将创建在/usr/local/apache/logs/%Y/%m/%d/access.log,其中%Y、%m、%d分别表示的是年、月、日。这些修饰符组成的文件名或目录被称为模板。
cronolog的轮替原理是:根据当前日志文件模板的时间点,和当前时间进行比较,如果模板中的某个部分和当前时间点的不同,则需要进行轮替,轮替时会自动创建缺失的目录,并且计算下一次进行轮替的时间点。在轮替时,先关闭当前日志文件,再根据当前时间点创建新日志文件,并打开新日志文件。但注意,cronolog工具在创建或轮替时,如果没有请求到达,则不会立即创建日志文件,这和rotatelogs工具的默认情况是一样的。
看上去很简单,确实很简单,它只需要根据指定的时间修饰符和当前时间点进行比较就可以了。例如上面的配置,如果当前时间点为2017-10-01,则按照以下顺序进行创建,注意,只有在请求到达时才会创建,没有请求时是不会创建的。
Period 1:在第一个请求到达时创建
logs/2017目录是否存在,不存在则创建。
logs/2017/10目录是否存在,不存在则创建。
logs/2017/10/01目录是否存在,不存在则创建。
创建logs/2017/10/01/access.log文件,并写日志。
Period 2:在2017-10-02凌晨第一个请求到达时创建
logs/2017目录已存在,不创建。
logs/2017/10目录已存在,不创建。
logs/2017/10/02目录不存在,创建。
创建logs/2017/10/02/access.log文件,并写日志。
之后将继续按照此规则不断进行下去。也就是说,cronolog默认将按照最小单位的时间修饰符为轮替时间间隔。例如,最小单位为%d时,将按照天轮替,最小单位为%W将按周轮替,最小单位为%S,将按秒轮替。但仍然需要说明的是,只有请求到达时,才会按照当前时间点创建新的日志文件。例如,如果按秒轮替,第10秒时创建了一个文件10.log,第11秒将关闭该日志文件,但是不会立即创建新日志文件,假设在第15秒时新的请求到达,则创建一个15.log,而不是11.log。
此外cronolog可使用"-p N UNITs"选项显式指定轮替时间间隔,有效单位UNITs为:seconds,minutes,hours,days,weeks和months。例如"-p 5 minutes"表示每5分钟轮替一次。但需要注意,N的值必须为更高一级UNITs的公因数(不包括最大公因数),例如小时的长度为60分钟,在指定minutes单位时,可以指定"1,2,3,4,5,6,10,15,20,30 minutes",但不能指定为"7,9,11,12,13,14"等minutes。
如果不想轮替,有两种方法:不要使用时间类的修饰符;使用"-o"选项。这时候会一直写同一个文件。
cronolog还支持动态符号链接功能,例如下面的配置,这样就使得每次访问/usr/local/apache/logs/access_log都能访问到最新的日志文件。
CustomLog "|/path/to/cronolog --symlink=/usr/local/apache/logs/access_log /usr/local/apache/logs/%Y/%m/access_log" combined
最后,cronolog不支持日志截断。
5、rotatelogs和cronolog的比较
这两个工具各有优缺点
在日志文件路径上:rotatelogs无法将时间类修饰符作为目录,只能使用在日志文件名上。而cronolog可以。例如logs/%Y%m/%d/access.log。
在日志控制力度上:rotatelogs对日志的控制力更强,它可以控制启动时、轮替时是否立即创建日志文件。而cronolog仅只能在有新请求到达时才创建日志文件。
在特性上:rotatelogs更丰富一些,它支持日志截断,支持在一定数量内循环轮替。而cronolog只能轮替,且只能按照时间不断向后轮替。
在日志访问方便性上:cronolog通过它的动态符号链接功能使得这一点比rotatelogs方便的多。
其实这些都是小问题。