zlog日志库(笔记) —— 介绍
zlog是什么?
zlog是一个高可靠、高性能、线程安全、灵活、概念清晰的纯C编写的开源日志库。
项目主页:http://hardysimpson.github.io/zlog/
github源码地址:https://github.com/HardySimpson/zlog
参考文档地址:http://hardysimpson.github.io/zlog/UsersGuide-CN.html
printf优点:使用简单、灵活。
printf缺点:同步输出,无法通过配置改变日志格式或输出文件。
syslog:系统日志或系统记录,速度慢,功能单调,而且系统所有进程都能往内部添加日志。
log4c也是一个纯C日志库,目前已停止更新。zlog在效率、功能、安全性上超过log4c(作者自称,未验证)。
zlog特点:
- syslog分类模型,比log4j模型更直接
- 日志格式定制,类似于log4j的pattern layout
- 多种输出,包括动态文件、静态文件、stdout、stderr、syslog、用户自定义输出函数
- 运行时手动、自动刷新配置文件(同时保证安全性)
- 高性能,在作者笔记本上可达25万条日志每秒,大约是syslog(3)配合rsyslogd的1000倍速度
- 用户自定义等级
- 多线程和多进程环境下保证安全转档
- 精确到微秒
- 简单调用包装dzlog(一个程序默认只用一个分类)
- MDC,线程键-值对的表,可以扩展用户自定义的字段
- 自诊断,可运行时输出zlog自己的日志和配置状态
- 不依赖其他库,不过系统需要支持POSIX + C99兼容的vsnprintf
zlog不做什么
zlog目标是成为一个精简的日志函数库,不支持网络输出或写入数据库,不支持日志内容的过滤和解析。
因为日志库是被APP调用,所以日志库运行时间是APP运行时间点一部分。而上述操作很费时,会拖慢APP。这些事情,应该在别的进程或机器上做。
如果想要这些特性(网络、数据库、日志归档),建议用rsyslog、zLogFabric、Logstash,这些日志搜集、过滤、存储软件。而这些也都是单独的进程,不是APP一部分。
zlog模型
分类、规则、格式
zlog 3个重要概念:分类(Category)、规则(Rule)、格式(Format)。
分类:用于区分不同的输入。分类变量的名字是一个字符串,APP可以通过不同的分类名称获取category,以输出不同分类的日志,用于不同目的。
格式:用于描述日志的格式,如是否带时间戳,是否包含文件位置信息等。
规则:把分类、级别、输出文件、格式组合起来,决定一条代码中的日志是否输出,输出到哪(文件/终端),以什么格式输出。
例如,当程序执行下面语句时,
zlog_category_t *c;
c = zlog_category("my_cat");
zlog_info(c, "hello, zlog");
zlog会找到分类c对象的名字是"my_cat",对应配置文件(.conf)中规则:
[rules]
my_cat.DEBUG >stdout; simple
当输出一条日志时,库会检查该日志级别是否符合规则中的级别要求:当前级别 >= DEBUG。如果满足,该条日志就输出。根据规则,日志会被输出到stdout(标准输出)。
输出格式simple,是什么样的呢?在配置文件中定义:
[formats]
simple = "%m%n"
最后,在屏幕(stdout)上打印:
hello, zlog
整个过程中,库用户需要做的就是写自己的信息。日志往哪输出,以什么格式输出,都是由库和配置文件来完成。
syslog模型 vs log4j模型
到目前为止,zlog采用的模型(category、rules、formats)还比较像log4j。log4j模型里有logger, appender, layout。区别在于:log4j里面,代码中的logger和配置中的logger是一一对应的,并且一个logger有唯一的级别。log4j, log4cxx, log4cpp, log4cplus, log4net都是一对一关系。
log4j模型缺点是不灵活。因此,发明了过滤器(filters)来弥补,但同时让模型更复杂、难以理解。
继前面例子,如果zlog配置文件(.conf)有这两条规则:
[rules]
my_cat.DEBUG >stdout; simple
my_cat.INFO >stdout;
一行输出日志的代码,会产生两行输出:
hello, zlog
2022-09-11 08:42:40 INFO [736:test_hello.c:30] hello, zlog
现在,代码中的同一个分类“my_cat"对应配置文件中两条规则。而在log4j中,需要放两个appender。
继续下面的例子。
配置文件:
[rules]
my_cat.INFO "/var/log/aa.log"
my_cat.DEBUG "/var/log/bb.log"
APP输出日志代码:
zlog_category_t *c;
c = zlog_category("my_cat");
...
zlog_info(c, "info, zlog");
zlog_debug(c, "debug, zlog");
最后,在aa.log中只有1条日志
$ sudo cat aa.log
2022-09-11 09:21:26 INFO [1410:test_hello.c:33] info, zlog
而在bb.log中有2条日志
$ sudo cat bb.log
2022-09-11 09:21:26 INFO [1410:test_hello.c:33] info, zlog
2022-09-11 09:21:26 DEBUG [1410:test_hello.c:34] debug, zlog
扩展syslog模型
现在,zlog模型似乎更像syslog模型。不过,syslog里的设施(facility)是int型,而且必须从系统定义的那几种选择(关于syslog,可参见这篇文章Unix/Linux syslogd守护进程 & 日志记录syslog )。zlog在此基础上,做了改善:可以用一个字符串来标识分类。
匹配设施
syslog有个通配符"",匹配所有的设施。zlog也采用了这种做法,""匹配所有分类。例如,只需要用一个很简单的办法,就能重定向系统种各个组件的错误:
[rules]
*.error "/var/log/error.log"
这样,
1)"*"会匹配所有分类(category);
2)只有级别高于error的日志消息,才会被输出到error.log文件中。
匹配级别
zlog一个强大特性是独有的上下级分类匹配。如果你的分类是这样:
zlog_category_t *c;
c = zlog_category("my_cat");
对应配置文件是这样:
[rules]
my_cat.* "/var/log/my_cat.log"
my_.NOTICE "/var/log/my.log"
这两条规则都会匹配c分类"my_cat"。配置文件中,通配符"-"标识上级分类,也就是说,"my_"是"my_cat"和"my_dog"的上级分类。
另一个通配符"!",见【分类匹配】部分。