开个新楼吧,日志转档、压缩和应用程序、库应该做什么。

难易 发布于 2012/07/27 20:01
阅读 1K+
收藏 0

@xiaomi_tc  

“这个办法分析过,如果文件大做复制的时候磁盘IO会有尖峰,如果机器上有其他进程可能会受影响。一种办法是在logrotate的postrotate中通知进程 reload 配置,只是需要每个进程都支持收信号,还要为每个进程写logrotate的配置文件。对小系统不是问题,多配置多种类型进程的系统会比较负责,迁移成本高另一种办法是修改zlog,当发现fd异常(文件不存在)时重新打开或者做reload”

1.zlog是应用程序调用的库,所以必须高效可靠的写日志,所以zlog本身不能做压缩,做文件大小检查和转档是唯一能高速调用的操作。

2.所以应该把压缩/或者转档交给别的进程去做,例如logrotate

3.logrotate的范式是,logrotate定期监控文件,然后发现条件符合(文件超大、日期过了一天等),然后做日志的转档和压缩工作。

   于是带来一些问题,例如上面所说的,需要重新写一份配置文件,重复zlog.conf已经有的信息……等等。

4.所以我的出发点是,是否zlog能通过某种方式发现日志条件改变,然后把信息传送给其他进程,由其他进程来做压缩转档的工作?也就是说是由zlog主动的通知其他进程。


问题:

1. 日志的转档、压缩存储软件有没有现成的好点的(能接受通知的而非轮询的)

2.其实换个角度讲,用户可以自己写函数挂在zlog上,通过用户自定义输出。因为zlog开放了自己的信息,写日志本身并不复杂,zlog只用了这么几行:

        if (write(a_rule->static_file_descriptor,
                        zlog_buf_str(a_thread->msg_buf),
                        zlog_buf_len(a_thread->msg_buf)) < 0) {
                zc_error("write fail, errno[%d]", errno);
                return -1;
        }

        if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) {
                a_rule->fsync_count = 0;
                if (fsync(a_rule->static_file_descriptor)) {
                        zc_error("fsync[%d] fail, errno[%d]", a_rule->static_file_descriptor, errno);
                }
        }

当然这几行是不会改变的,这是唯一高效写日志的方法,任何多余的操作只会损失效率。

用户可以自己写一些程序,在里面调用system等方法来产生子进程,做压缩,转档的工作。。

如果用户能提炼出一套范式,那我想zlog可以吸收部分,但我很怀疑,毕竟不同的环境下有不同的需求,在转档和压缩方面,而这是很难“标准化“的


加载中
0
难易
难易
记得哪个家伙说过来着,

Good Artists Borrow, Great Artists Steal

——毕加索

今天打算调研一下其他的日志函数库和程序是怎么管理日志的转档和压缩的。

0
难易
难易

首先是NLOG的,NLOG是个c#版的巨大怪兽

每10kb转档一次,顺序写(00,01,02,03,最新的是03),

<?xml version="1.0" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 
    <targets>
        <target name="file" xsi:type="File"
            layout="${longdate} ${logger} ${message}" 
            fileName="${basedir}/logs/logfile.txt" 
            archiveFileName="${basedir}/archives/log.{#####}.txt"
            archiveAboveSize="10240"
            archiveNumbering="Sequence"
            concurrentWrites="true"
            keepFileOpen="false"
            encoding="iso-8859-2" />
    </targets>
 
    <rules>
        <logger name="*" minlevel="Debug" writeTo="file" />
    </rules>
</nlog>

每天转档一次,轮转(00,01,02,00是最新的),保持7个日志

<?xml version="1.0" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 
    <targets>
        <target name="file" xsi:type="File"
            layout="${longdate} ${logger} ${message}" 
            fileName="${basedir}/logs/logfile.txt" 
            archiveFileName="${basedir}/archives/log.{#}.txt"
            archiveEvery="Day"
            archiveNumbering="Rolling"
            maxArchiveFiles="7"
            concurrentWrites="true"
            keepFileOpen="false"
            encoding="iso-8859-2" />
    </targets>
 
    <rules>
        <logger name="*" minlevel="Debug" writeTo="file" />
    </rules>
</nlog>

归纳一下,转档功能为:

archiveAboveSize: 文件大小

maxArchiveFiles: 保留文件个数

archiveFileName:转档文件名 {#####} 代表数字编号

archiveNumbering:Rolling,轮转;Sequence,升序

archiveEvery:每多少时间轮转一次,Day,Hour,Minute,Month,None,Year,时间点的改变。

压缩支持:无,不过作者在论坛里面提了一下

http://nlog-forum.1685105.n2.nabble.com/Compress-amp-Delete-old-logs-td1685211.html

0
难易
难易

接下来是老牌软件,事实标准logrotate,主页上的例子稍微简单了一点

找到一篇blog描述的还不错的:

http://blog.csdn.net/sz_liao/article/details/7418584

参数 功能

compress 通过gzip 压缩转储以后的日志

nocompress 不需要压缩时,用这个参数

copytruncate 用于还在打开中的日志文件,把当前日志备份并截断

nocopytruncate 备份日志文件但是不截断

create mode owner group 转储文件,使用指定的文件模式创建新的日志文件

nocreate 不建立新的日志文件

delaycompress 和compress 一起使用时,转储的日志文件到下一次转储时才压缩

nodelaycompress 覆盖delaycompress 选项,转储同时压缩。

errors address 专储时的错误信息发送到指定的Email 地址

ifempty 即使是空文件也转储,这个是logrotate 的缺省选项。

notifempty 如果是空文件的话,不转储

mail address 把转储的日志文件发送到指定的E-mail 地址

nomail 转储时不发送日志文件

olddir directory 转储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统

noolddir 转储后的日志文件和当前日志文件放在同一个目录下

prerotate/endscript 在转储以前需要执行的命令可以放入这个对,这两个关键字必须单独成行

postrotate/endscript 在转储以后需要执行的命令可以放入这个对,这两个关键字必须单独成行

daily 指定转储周期为每天

weekly 指定转储周期为每周

monthly 指定转储周期为每月

rotate count 指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份

tabootext [+] list 让logrotate 不转储指定扩展名的文件,缺省的扩展名是:.rpm-orig, .rpmsave, v, 和~

size size 当日志文件到达指定的大小时才转储,Size 可以指定bytes (缺省)以及KB (sizek)或者MB (sizem).

 

例子如下:

       /var/log/news/* {
           monthly
           rotate 2
           olddir /var/log/news/old
           missingok
           postrotate
               kill -HUP `cat /var/run/inn.pid`
           endscript
           nocompress
       }

0
难易
难易

接下来,是cronolog,apache推荐的一个软件,从原理上来说,这个软件完全符合unix设计哲学,就是他从标准输入读取日志,然后按照天之类的来分割。可惜,这个思路在zlog来说是完全实现了的,并且zlog做得更多一些,可以支持更多的转换字符(当然会有一定的性能损失)。

应用程序输出到管道,cronolog监听管道的方式会是高效的吗?我决定测试一下……

http://skymax.blog.51cto.com/365901/132475/

结果是:

$ time ./test_press_write 1 10 100000 | /usr/bin/cronolog press%Y.log

real	0m0.587s
user	0m0.110s
sys	0m0.690s

$ time ./test_press_zlog 1 10 100000 | /usr/bin/cronolog press%Y.log

real	0m1.549s
user	0m1.790s
sys	0m0.780s

相比用zlog直接写日志还要快!zlog的数据是

$ time ./test_press_zlog 1 10 100000
real    0m2.334s
user    0m1.780s
sys     0m2.710s

不过这倒不是很让人吃惊,因为前面套了管道,而管道是unix下速度最快的IPC了,具有缓冲作用。

不过管道有一些问题:

1.系统保证读写不大于PIPE_BUF 大小的内容是原子的。linux上PIPE_BUF为4096。

2.管道的容量不等于PIPE_BUF,linux 2.6.11 以前,是4096,以后是65536。当管道满时,根据是否阻塞,write阻塞或者失败。

也就是说,在这种方式下需要由用户来保证单条日志的长度不超过4K,才能保证是原子的。。嗯,这点很重要,我开始考虑在zlog里面实现管道了。。

不过很可惜的是,cronlog同样没有解决日志交错的问题,这就是快的代价……,这点对多进程多线程写同一个日志文件极为重要。

也就是zlog已经考虑过的问题,很简单,对于从管道中读取的数据,他无法分辨单条日志的边界。

于是在多个进程写同一个日志的情况下,就不行了……

$ cat aa.sh
time ./test_press_zlog 1 10 100000 | /usr/bin/cronolog press.log &
time ./test_press_zlog 1 10 100000 | /usr/bin/cronolog press.log &
time ./test_press_zlog 1 10 100000 | /usr/bin/cronolog press.log &

日志交错现象

$ awk '{if (length(max)<length()) max=$0}END{print max}' press.log 
2012-07-28 15:27:34.218641 INFO   28669:140501717370624:test_press_zlog.c:36 log2012-07-28 15:27:34.218127 INFO   28647:140045180385024:test_press_zlog.c:36 loglog

0
killer007
killer007
请问按天分日志功能是否具备? 还有就是按大小分日志?
难易
难易
zlog可以在日志文件名里面包含自动生成的日期,也支持按照大小来转档。
0
难易
难易

接下来是rsyslog,我个人认为的syslog的接班人,实际上在ubuntu上用rsyslog来代替syslog。syslog-ng是商业产品,不考虑。

可惜rsyslog在转档方面的支持程度很低,仅仅支持转档一次,旧的就删掉了,只支持文件大小转档。

链接:

http://www.rsyslog.com/doc/log_rotation_fix_size.html

语法:

# start log rotation via outchannel
# outchannel definiation
$outchannel log_rotation,/var/log/log_rotation.log, 52428800,/home/me/./log_rotation_script 
#  activate the channel and log everything to it 
*.* :omfile:$log_rotation
# end log rotation via outchannel

作者也承认,rsyslog同样需要logrotate来做转档和压缩的活

http://www.gossamer-threads.com/lists/rsyslog/users/2536

 

Re: Time of rotation? [In reply to]
rsyslog does not do any rotation on its own (except if you use output 
channels and explicitely define this. Usually, logrotate is used to rotate 
files. So this looks like a problem with your config. 

Rainer 
Aug 24, 2009, 2:10 AM  

0
难易
难易

最后是logback,和log4j是同一个作者,所以在这里就不需要再看log4j了。

zlog也从log4j偷窃了mdc(这个名字我还是很讨厌……),这是一个良好的设计。

说实话我讨厌log4j和logback的总体设计,配置文件臃肿难以理解,接口繁杂,看起来很有“企业级软件“的样子,但不得不说这是目前世界上最流行的日志函数库,是印度人写的,非常善于推销自己的作品。

言归正传,logback的转档和压缩是这么干的,分3种:

1. FixedWindowRollingPolicy ---- fileNamePattern

例如,对于最小值和最大值分别是 1 和 3 的文件名模式“MyLogFile%i. log”会产生归档文件 MyLogFile1.log、,MyLogFile2.log 和 MyLogFile3.log。该 属 性 还 可以 指 定文 件 压 缩选 项 。例 如“MyLogFile%i.log.zip”表示归档文件必须用 zip 格式进行压缩;还支持“.gz”格式。

2. TimeBasedRollingPolicy 

fileNamePattern

必需。定义滚动(归档)记录文件的名字。其值应当包含文件名及“%d”格式转换符。“%d”可以包含一个java.text.SimpleDateFormat 指定的日期时间模式。如果没有指 定日期 时间模 式, 则默认 为 yyyy-MM-dd。RollingFileAppender(TimeBasedRollingPolicy 之父)的“file”选项可有可无。

通过设置“file”属性,可以为活动文件和归档文件指定不同的位置。当前记录总是被指向由“file”属性指定的文件。如果有“file”属性,则活动文件的名字不

会改变。而如果没有“file”属性,则活动文件的名字会根据“fileNamePattern”的值每隔一段时间就重新计算一次。下面的例子会解释这点。

“ %d{} ” 里 的 日 期 时 间 模 式 遵 循java.text.SimpleDateFormat 的约定。在 fileNamePattern或日期时间模式里的前置“/”或后置“\”会被当作目录分隔符。

maxHistory

控制被保留的归档文件的最大数量,超出数量就删除旧文件。例如,假设每月滚动,且 maxHistory 是 6,则只保留最近 6 个月的归档文件,删除之前的文件。注意当删除旧归档文件时,那些为了归档而创建的目录也会被删除。

正如 FixedWindowRollingPolicy,TimeBasedRollingPolicy 支持自动压缩文 件。如果“fileNamePattern”选项以“.gz”或“.zip”结尾,就表示需要压缩。

3基于大小和时间的归档
SizeAndTimeBasedFNATP

<configuration>
<appender name="ROLLING"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>mylog.txt</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="ROLLING" />
</root>
</configuration>

看,又是一堆xml……

0
xiaomi_tc
xiaomi_tc

4.所以我的出发点是,是否zlog能通过某种方式发现日志条件改变,然后把信息传送给其他进程,由其他进程来做压缩转档的工作?也就是说是由zlog主动的通知其他进程。

    这个一种思路。如果zlog能发现日志条件的改变,可以直接重新open 或 reload

另一种思路还是日志外监控日志文件变化。用 inotify 监听日志文件事件,如果文件有变动再重新调用reload。这种方法可以在保证zlog纯洁性的同时解决用logrotate带来的转档过程的问题。 缺点是需要改应用程序以加入对inotify事件的监听和处理,比较难成合入到库中。但可以考虑作为一种通用用法在文档中说明一下或给个简单示例

难易
难易
这个对于重载配置文件倒是不错,呵呵。转档日志文件就算了。
0
xiaomi_tc
xiaomi_tc

在Makefile 中加入 -D_FILE_OFFSET_BITS=64 , 以防linux 32位系统的2G文件限制

难易
难易
在1.2.0版中已经加了,谢谢
返回顶部
顶部