早天看到一遍关于JDK日志层级的文章,原文:

http://tutorials.jenkov.com/java-logging/logger-hierarchy.html

一路被这个文章讲的晕头转向。什么 forward,Passed,propagated等等。

JDK为什么把他设计的那么复杂,今天看一下JDK的代码。发现他测试的结果是对的,但讲法的差强人意。

Java Logger层次结构补充_第1张图片

日志结构却如上图树形所示,但Logger之间的父子关系是通过单独的索引结构表示的。如上图红色线表示logger(com.jenkoe.web)的父logger为rootlogger,在寻祖的过程中,中间结点若是虚结点,由直接跳过。这就是文件所说的:

 if you do create a Logger like this:

Logger logger  = Logger.getLogger("com.jenkov.web");

... and call getParent() method, you will get the Logger with the name "".

一旦中间的结点有值(由虚变实)需要更新其孩子结点的父索引(具体可看LogContext.addLocalLoader源码)。


再说Filter的传递问题,文件讲得太不好理解有两个点:

  1.  accept or reject 只发生在当前logger的filter上,若当前logger无filter,则accept。

  2. 若当前logger accept这个日志,则传播到上层logger,一直到根。

太晦涩,看代码:

  public void log(LogRecord record) {
        if (!isLoggable(record.getLevel())) {
            return;
        }
        Filter theFilter = filter;
        if (theFilter != null && !theFilter.isLoggable(record)) {
            return;
        }

        // Post the LogRecord to all our Handlers, and then to
        // our parents' handlers, all the way up the tree.

        Logger logger = this;
        while (logger != null) {
            final Handler[] loggerHandlers = isSystemLogger
                ? logger.accessCheckedHandlers()
                : logger.getHandlers();

            for (Handler handler : loggerHandlers) {
                handler.publish(record);
            }

            final boolean useParentHdls = isSystemLogger
                ? logger.useParentHandlers
                : logger.getUseParentHandlers();

            if (!useParentHdls) {
                break;
            }

            logger = isSystemLogger ? logger.parent : logger.getParent();
        }
    }

只用调用当前logger的filter,则所谓的传播是useParentHandler属性在起做作用,若为true,则递归调用祖辈logger的Handler,没有父logger的filter什么事。


在下面关于日志级别的问题,正如上面的代码。只在当前logger里进行了级别检查, 也没传播与否的说法。

文中:

Logger logger      = Logger.getLogger("");
Logger logger1     = Logger.getLogger("1");
Logger logger1_2   = Logger.getLogger("1.2");

logger1  .setLevel(Level.WARNING);
logger1_2.setLevel(Level.INFO);

logger     .info("msg:");
logger1    .info("msg: 1");
logger1_2  .info("msg: 1.2");

The result of this code is that the INFO message logged on the bottom Logger (named 1.2) is now logged, but it is still not propagated up the hierarchy. Well, it is, but the middle Logger filters it out, because the middle Loggerhas a log level of WARNING set. Thus, the message is not logged by the middle Logger nor propagated up the hierarchy.


不知道作者是否代码粘错了。这里没有propagated, 并不是middle Logger的level问题,而是因为  middle Logger和bottom Logger 都没有指定handler。最后全都传导到Root logger(它有默认的handler)。

若代码改成:

Logger logger      = Logger.getLogger("");
Logger logger1     = Logger.getLogger("1");
Logger logger1_2   = Logger.getLogger("1.2");

logger1    .addHandler(new ConsoleHandler());
logger1_2  .addHandler(new ConsoleHandler());
logger1  .setLevel(Level.WARNING);
logger1_2.setLevel(Level.INFO);

logger     .info("msg:");
logger1    .info("msg: 1");
logger1_2  .info("msg: 1.2");

结果就是:

九月 05, 2017 4:29:15 下午 java.util.logging.LogManager$RootLogger log
信息: msg:
九月 05, 2017 4:29:15 下午 guojje.SAPITest main
信息: msg: 1.2
九月 05, 2017 4:29:15 下午 guojje.SAPITest main
信息: msg: 1.2
九月 05, 2017 4:29:15 下午 guojje.SAPITest main
信息: msg: 1.2

所以很多费解的文章都是有问题的。