-
Notifications
You must be signed in to change notification settings - Fork 721
为什么log4j的概念模型是错误的——zlog的模型简介
假设你的log4j系统中有这样的配置:
log4j.logger.aa=ERROR, A1
log4j.logger.aa.bb=
log4j.logger.aa.cc=INFO
aa是一个父logger。aa.bb和aa.cc是aa的子logger。
aa.bb继承了aa's等级和输出(appender),等级是ERROR输出是A1。
aa.cc继承并覆盖了aa的级别。所以aa.cc的等级是INFO输出还是A1。
需求1:如果我现在想把所有的aa的日志,所有的级别,输出到一个特别的文件里面去,并保持原来的aa.bb、aa.cc的输出不变,如何实现?
需求2:假设我动了aa.bb的代码,想在生产上把aa.bb的所有日志,从DEBUG级别开始输出到某个aa.bb.debug.log,而保持aa的ERROR以上级别的日志不动(方便运维人员不改变他们的习惯,直接看原来的日志)
log4j将会如何实现这些需求?很困难,也许要在appender上引入阈值(threshold),或者引入子logger不继承父logger的选项。子logger可以自己指定一个等级,或者从父logger那里继承一个。但说到底,log4j的logger必须有且只能有一个等级,等级和logger是绑定的。
zlog将会如何实现这些需求?首先,zlog继承了syslog配置文件的思想,一个分类的不同等级可以同时存在不同的规则内。这就让过滤同一分类的不同等级的日志到不同日志文件成为可能。
aa.debug "/var/log/aa.debug.log"
aa.=notice "/var/log/aa.notice.log"
是不是觉得自由了很多?
其次,在zlog里面,所有的规则之间都是独立的,没有父子关系。纲目分类的关系表现在分类字符串中间的下划线。举例:
#rule 1
aa_bb.DEBUG "/var/log/aa_bb.log"
#rule 2
aa_cc.INFO "/var/log/aa_cc.log"
#rule 3
aa_.ERROR "/var/log/aa_error.log"
#rule 4
aa.* "/var/log/aa.log"
没有继承,只有4条独立的规则
如果代码里面的分类名是"aa_bb"。代码就像这样:
category_t ab;
ab = zlog_get_category("aa_bb");
ZLOG_DEBUG(ab, "ab's debug");
ZLOG_ERROR(ab, "ab's error");
配置中,rule 1的分类字符串aa_bb和rule 3的分类字符串aa_,与代码中的名字为aa_bb的分类变量是匹配的。于是代码中属于aa_bb分类变量、>=DEBUG日志输出到aa_bb.log,属于aa_bb分类变量、>=ERROR会被输出到 aa_error.log。ERROR等级的日志会被同时写在两个文件里面。不过rule 4的变量字符串是aa,它不匹配分类变量aa_bb,它精确匹配拥有aa名字的分类变量。
这就是纲目分类模型。规则和规则之间是分开的。一个代码分类变量可以匹配多个规则分类字符串,一个规则可以属于多个代码分类变量。规则中的纲分类字符串(以下划线结尾的)匹配代码中的目分类变量,纲分类字符串的范围包括了了目分类字符串。这样,用户可以选择任意范围的纲目分类字符串来输出,而不影响其他规则的行为。
事实上,在zlog_get_category()被调用的时候,并不保证代码分类变量一定有相匹配的规则分类字符串。分类变量可以有很多与之匹配的规则,也有可能一条都没有,这取决于配置文件是怎么写的。当配置文件改变并调用zlog_reload()后,代码分类变量和规则分类字符串的匹配会被重新计算。根据上面所说的匹配方式,每个分类变量都会从新的配置文件里面找到自己的新规则。
也就是说,在zlog里面,多输出是由多条规则来实现的,而不是log4j的多个appender。一条规则代表程序员对于某种分类和等级的日志的输出需求。没有必要指定某个分类必须为什么等级。分类、等级、输出这3者可以自由搭配,完全解耦,这样就带来了极大的灵活性。
必须感谢unix系统syslog的设计者。从思想上来说,zlog只是在他们的基础上增加了一点点的改动来匹配纲目分类,但灵活性远超java系列的绑定思想。也许log4j的设计者被继承这两个字晃花了眼,以为继承就是解决一切问题的灵丹妙药……