【原】zlog,软件项目中日志管理模块的不二之选

 

让zlog提供日志管理,支持你的工程项目

 

在最近做的项目中,考虑到项目后期存在越做越大,越大越不好维护的必然性,我就想给工程加一个日志管理模块,以便作用于整个系统的运维管理。我漫天查找,大部分网友建议用zlog,说zlog比log4c在效率,功能,安全等方面都有很大的提高,而且相比较syslog而言,虽然zlog采用syslog的分类模型,但是功能上比syslog更多元。想想以前公司的项目,模糊记得好象是用zlog,于是乎赶紧找资料,耗时一天(主要是C99标准兼容的vsnprintf使坏),包括编译,试运行,移植,与项目合并都顺利完成了,我很高兴zlog为我的代码积累添砖加瓦。下面,用简短的文字,描述一下我在移植合并zlog的过程中,遇到的问题和解决办法。

 

什么是zlog

zlog是一个纯C 日志库。C行业尤其是嵌入式C行业,有没有特别好的公认的日志系统,我不清楚,只是知道大家习惯上用log4c,或者是syslog系统级的日志系统,或者纯粹用printf。

下面综合网上的分析,以及自己的亲身实验,总结zlog的以下几点特点(但是具体哪个更适合你,更适合在嵌入式,看实际情况而定):

  • syslog分类模型,比log4j模型更加直接了当

  log4j简单用过,确实比较繁琐;

  • 日志格式定制

  zlog的日志输出格式可以根据自己的需要灵活设置

  • 多种输出,包括动态文件、静态文件、stdout、stderr、syslog、用户自定义输出函数

  zlog完成的日志输出很灵活,自定义文件,标准文件等都能很好支持,在配置文件中能够指定输出目的

  • 运行时手动、自动刷新配置文件(同时保证安全)

  没试过。可能是说在程序运行中,更新配置文件,修改后新的配置生效???

  • 高性能

  每秒数十万的日志记录,性能上应该能够满足。

  • 用户自定义等级

  这点很方便,在配置文件中新定义日志级别,这样大于该级别的日志将会根据规则,以及预定义的格式输出,小于该级别的日志则不会。

  • 多线程和多进程环境下保证安全转档
  • 精确到微秒

  在doc下的文档中就能看出来,自己没时间试

  • 不依赖其他库,只要是个POSIX系统就成(当然还要一个C99兼容的vsnprintf)

  这点在后面有介绍。

 

zlog的分类、规则和格式

zlog读取某个配置文件,该配置文件内部定义了各种分类,用以区分不同的输入;格式确定日志的输出格式;规则把分类、级别、输出文件、格式组合起来,决定一条代码中的日志是否输出,输出到哪里,以什么格式输出等。源码的doc目录下有一个zlog.conf文件,该文件作为一个基本构架,详细列出了zlog的很多特点。

 

主机下载编译

下载

源码下载:https://github.com/downloads/HardySimpson/zlog/zlog-latest-stable.tar.gz, 或者

作者博客可用版本:http://files.cnblogs.com/iTsihang/zlog-latest-stable.tar.zip

 

解压、编译和安装

解压后,编译,安装(在源码目录下的README都有介绍,不在此介绍)。不需要交叉编译的在主机下直接编译就行。

现在zlog默认会被编译成动态库和静态库两类。但是在编译编译静态库过程中,会出现找不到pthread中定义的方法的错误,其实这已经不影响我们做后面的事情,查看编译输出内容你会发现,至少现在zlog已经被编译成动态库了。

 

编译测试例子

为了测试当前编译结果,编译完后,执行 “ make test ”,这样会在test目录下生成很多测试例子,这些例子介绍了zlog支持的对象—格式,规则,模板等。编译后,进入test目录,运行测试例子。

 

交叉编译和移植

我使用zlog,主要是移植,并为某项目提供日志管理,所以不会安装在系统中。大多情况下,包括我们在设计嵌入式程序,交叉编译的时候,交叉编译链对C99的支持并不是很好。为了兼容gcc编译和交叉编译,有两种途径用以实现:

 

使用snprintf.c源文件

这个在网上可以下载到,http://www.oschina.net/code/explore/freebsd/contrib/libpcap/missing/snprintf.c, 或者 http://files.cnblogs.com/iTsihang/snprintf.zip。直接添加到工程中即可,但是我基本上不用,因为无缘无故增加了文件数量(至少两个)

 

修改部分文件

修改部分文件也能完成。

1> 声明和定义兼容宏

我在zc_defs.h中做了如下声明和宏定义[实现交叉编译]

 1 #ifndef HAVE_SNPRINTF  2  3 int snprintf(char *, size_t, const char *, ...);  4  5 #endif  6  7 #ifndef HAVE_VSNPRINTF  8  9 #define vsnprintf(buf, size, format, args) vsprintf(buf, format, args) 10 11 #end

该宏声明vsnprintf为通用vsprintf,从二者的参数可见C99对字符串的处理更加谨慎,因为它注意到串长度。

修改这样一来,交叉编译可以顺利通过,但是,转回来不用交叉编译却出现了问题:

1 In file included from rule.h:28:0, 2 3 from category.c:25: 4 5 /usr/include/stdio.h:395:6: error: format string argument is not a string type

这是因为/usr/include/stdio.h中声明的vsnprintf和我们使用的接口不一致。

为了同时能在主机上编译和交叉编译,请这样做:

2> 将/usr/include/stdio.h的386至397注释掉

这样一来,zlog就是一个混合型C99标准工程了。重新编译。

 

其他修改

因编译静态库造成的错误很可能误导大家,所以我就从Makefile中把编译静态库的部分去掉,直接做成动态库使用

修改后的工程下载:http://files.cnblogs.com/iTsihang/zlog-1.2.3-m.tar.zip

 

在原项目工程的架构(Makefile)中,指定zlog的编译路径,将zlog编译成动态库后,在原工程链接的时候引用,再将test_XX例子的代码复制到主方法中,指定新的config路径,重新编写了分类、规则和输出格式配置项。无误后,编译整个工程

我的日志配置文件如下:

 1 [global]  2 strict init = true  3 reload conf period = 10M  4  5 buffer min = 1024  6 buffer max = 2MB  7  8 #rotate lock file = /tmp/zlog.lock  9 rotate lock file = self 10 default format = "%d(%F %T.%l) %-6V (%c:%F:%L) - %m%n" 11 12 file perms = 600 13 fsync period = 1K 14 15 [levels] 16 TRACE = 110 17 CRIT = 130, LOG_CRIT 18 19 [formats] 20 simple = "%m%n" 21 normal = "%d(%F %T.%l) %m%n" 22 23 [rules] 24 #default.* >stdout; simple 25 26 *.* -"%12.2E(HOME)/log/%c.log", \ 27 1MB * 12 ~ "%E(HOME)/log/%c.%D(%F) #2r #3s.log"; \ 28  simple 29 30 #my_.INFO >stdout;    # log category which filtered by "my_" to stdout with level > INFO 31 32 #my_cat.!ERROR "YOUR_PATH/run.log" # log who's level is not an ERROR level to YOUR_PATH/run.log. 33 #my_cat.ERROR "YOUR_PATH/err.log" # log who's level is greater than ERROR to YOUR_PATH/err.log.  34 my_cat.TRACE >stdout; simple # log who's level is greater than TRACE=110 to stdout (only fatal). 35 my_cat.WARN >stdout # log who's level is greater than WARN to stdout.  36 my_cat.DEBUG >stdout; normal # log who's level is greater than DEBUG to stdout with defalut format 37 38 #my_dog.DEBUG >stdout; # another category named my_dog

 

Q&A

我现在的移植相当简单,但是作为一个项目框架,各个模块之间的关联务必要谨慎。我将zlog加进项目工程中,也考虑到后期拆分或者其他可能性,总之尽可能的减少模块之间的依赖。现在增删模块也比较方便,还是不错的。有时间,有想法的时候,再改进改进项目的构架,这样以后,距离一个比较靠谱的中小型工程就越来越近了。

你可能感兴趣的:(log)