夕辞

Apache log4j学习之二:日志级别层级继承 | 夕辞夕辞

Apache log4j学习之二:日志级别层级继承

上节介绍日志级别的顺序,知道了日志打印请求的级别必须大于或等于当前logger的日志级别才能打印出,这次来学习下日志级别的层级继承关系。

我们先看示例代码:

package com.zhuzhuodong.share.log4j.lesson2;

import com.zhuzhuodong.share.log4j.util.SystemUtil;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

public class Lesson2 {

    public static void main(String[] args) {
        BasicConfigurator.configure();
        Logger rootLogger = Logger.getRootLogger();
        rootLogger.setLevel(Level.INFO);
        SystemUtil.systemErrPrintlnLogLevel(rootLogger);

        Logger a = Logger.getLogger("a");
        //查看a默认级别及日志打印
        SystemUtil.systemErrPrintlnLogLevel(a);
        a.debug("a.debug");
        a.info("a.info");

        //设置a日志级别为debug
        a.setLevel(Level.DEBUG);
        SystemUtil.systemErrPrintlnLogLevel(a);
        a.debug("a.debug");
        a.info("a.info");

        //取消a日志级别设置
        a.setLevel(null);
        SystemUtil.systemErrPrintlnLogLevel(a);
        a.debug("a.debug");
        a.info("a.info");

        //定义子级logger ab
        Logger ab = Logger.getLogger("a.b");
        SystemUtil.systemErrPrintlnLogLevel(ab);
        ab.debug("ab.debug");
        ab.info("ab.info");
        ab.warn("ab.warn");

        //设置a为warn
        a.setLevel(Level.WARN);
        SystemUtil.systemErrPrintlnLogLevel(a);
        SystemUtil.systemErrPrintlnLogLevel(ab);
        ab.debug("ab.debug");
        ab.info("ab.info");
        ab.warn("ab.warn");

        //设置a为null,提高root级别
        a.setLevel(null);
        rootLogger.setLevel(Level.ERROR);
        SystemUtil.systemErrPrintlnLogLevel(rootLogger);
        SystemUtil.systemErrPrintlnLogLevel(a);
        SystemUtil.systemErrPrintlnLogLevel(ab);
        ab.debug("ab.debug");
        ab.info("ab.info");
        ab.warn("ab.warn");
        ab.fatal("ab.fatal");

        //设置ab级别为debug
        ab.setLevel(Level.DEBUG);
        SystemUtil.systemErrPrintlnLogLevel(rootLogger);
        SystemUtil.systemErrPrintlnLogLevel(a);
        SystemUtil.systemErrPrintlnLogLevel(ab);
        ab.debug("ab.debug");
        ab.info("ab.info");
        ab.warn("ab.warn");
        ab.fatal("ab.fatal");
    }

}

然后贴出控制台输出内容:

# SERR: logger:root	level:INFO	effectiveLevel:INFO
# SERR: logger:a	level:null	effectiveLevel:INFO
0 [main] INFO a  - a.info
# SERR: logger:a	level:DEBUG	effectiveLevel:DEBUG
103 [main] DEBUG a  - a.debug
103 [main] INFO a  - a.info
# SERR: logger:a	level:null	effectiveLevel:INFO
208 [main] INFO a  - a.info
# SERR: logger:a.b	level:null	effectiveLevel:INFO
317 [main] INFO a.b  - ab.info
317 [main] WARN a.b  - ab.warn
# SERR: logger:a	level:WARN	effectiveLevel:WARN
# SERR: logger:a.b	level:null	effectiveLevel:WARN
531 [main] WARN a.b  - ab.warn
# SERR: logger:root	level:ERROR	effectiveLevel:ERROR
# SERR: logger:a	level:null	effectiveLevel:ERROR
# SERR: logger:a.b	level:null	effectiveLevel:ERROR
846 [main] FATAL a.b  - ab.fatal
# SERR: logger:root	level:ERROR	effectiveLevel:ERROR
# SERR: logger:a	level:null	effectiveLevel:ERROR
# SERR: logger:a.b	level:DEBUG	effectiveLevel:DEBUG
1169 [main] DEBUG a.b  - ab.debug
1170 [main] INFO a.b  - ab.info
1170 [main] WARN a.b  - ab.warn
1170 [main] FATAL a.b  - ab.fatal

 

我们主要验证以下几点:

1.root logger默认级别debug,其他logger为分配级别时为空;

2.在logger都没有分配级别时,继承root logger的级别;

3.在logger分配级别时,无论父级别或祖先级别是否有分配,都以logger分配级别;

4.logger未分配级别时,向上找父logger直至root logger,以离logger最近的父logger级别为准

 

以上验证的几点从例子的输出也可以看出,刚开始未设置a级别,则以root为准;设置a的级别后,以a为准;a级别设置为null后,以root为准;ab级别最初设置因为a没有设置级别,以root为准;设置a的级别为warn,则ab继承了a的级别;设置a级别为null并设置root级别为error,ab继承root的级别;设置ab级别为debug后,以ab本身级别为准。

 

接下来我们研究下这个层级的继承是如何实现的,源码:

public Level getEffectiveLevel() {
	for(Category c = this; c != null; c=c.parent) {
		if(c.level != null)
			return c.level;
    }
    return null; // If reached will cause an NullPointerException.
}

源码逻辑也比较简单,Logger是继承了Category类的,Category类我们关注的两个属性是level、parent,level是级别,parent是父logger,通过循环一直向上查询,直到查询到level不为空的logger,这个level即为logger最终的level。

还有一点我们注意到注释中写如果返回null,会抛出异常,这也是为什么root logger的level无论使用log4j.xml还是log4j.properties文件配置,都必须设置root logger的级别,相当于对整个代码的统一设置。

回到顶部