Skip to content

Why log4j's model is wrong? A introduction of zlog's model

HardySimpson edited this page Mar 2, 2013 · 6 revisions

Assume there is a log4j configure file in your system like this:

log4j.logger.aa=ERROR, A1

log4j.logger.aa.bb=

log4j.logger.aa.cc=INFO

aa is a father logger. aa.bb and aa.cc is the child of aa.

aa.bb inherits aa's level and appender, which are ERROR and A1.

aa.cc inherits and overwrite aa's level. So aa.cc has the level of INFO and appender of A1.

Two demand here.

1st, If I want all aa's log output to a special file (and keep output of aa.bb and aa.cc not changed)?

2rd, If I change aa.bb's code, I want all aa.bb's log above DEBUG level direct to aa.bb.debug.log, and watches it carefully for a period. But at the same time, keep aa's ERROR log not changed to fit operating personnel's habbits.

How can log4j do that job? Very hard, maybe need set threshold, maybe set aa.bb's additivity to false. That's really hard, because in log4j, each logger must have a level, maybe decide itself, or inherit from its parent. But in the end, there can be only one level for each logger, no more.

How can zlog do that job? First, zlog allows each category could have multiple levels. For example

aa.debug         "/var/log/aa.debug.log"
aa.=notice       "/var/log/aa.notice.log"

Is that make you ease?

Second, in zlog, all rules are independent, NO heritage. Range-category relationship is express as a underline in category string. For example:

#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"

There is no heirship here, just 4 sperate rules. If the name of category in source is "aa_bb". The c source file is like this.

category_t ab;

ab = zlog_get_category("aa_bb");
ZLOG_DEBUG(ab, "ab's debug");
ZLOG_ERROR(ab, "ab's error");

Then category string in rule 1 and rule 3, which are "aa_bb" and "aa_", match the category variable in source file, whose name is "aa_bb". These two rules determine that aa_bb's >=DEBUG log action in source will be output to aa_bb.log, and aa_bb's >=ERROR log action in source will be output to aa_error.log. ERROR log will be written in both files. But rule 4 doesn't match the category. It's category string is "aa", which accurately matches the category variable whose name is "aa".

That is the range-category model. Rule and rule are sperate. Each source category variable has its rules, one rule may belong to different soure category variable. Rule-super-category-string(with '_') matches all source-sub-category-variable, so super-category-string range contains sub-cateogry-string range. At a result, user could select any range in configure file, matches big or small of categories for output, but not affect other rules' action.

In fact, when zlog_get_category() is called, there is NO guarantee that the category must contains rules. It may have many matching rules, or may have none. That depends on how configure file is written. After the configure file is changed and zlog_reload() is called, the relationship between categories and rules will be re-calculated. Each Category will get its new matching rules, in the way described above.

In zlog, multiple output is done by multiple rules, not by multiple appender as log4j does. One rule represents a programmer's intention of output for identified category with identified level. No need to assign constant level to each category. Category, level, Output can be combined free. That takes flexible.

Here I should thank to designer of syslog. zlog just make a small step(string category, sub-category) behind syslog, but is far more flexible than log4j. Maybe log4j is written by java and the author are fascinated by inheritance, think it the answer to everything...

btw, I just find nlog(a c# logging library) has the same model as zlog now.