Java日志记录:记录器的层次结构

时间:2020-01-09 10:36:45  来源:igfitidea点击:

应用程序中使用的"记录器"通常按层次结构进行组织,如本教程其他地方所述。本文将仔细研究此Logger层次结构的工作方式。

创建Logger时,我们将名称传递给Logger.getLogger()方法。这是一个例子:

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

在此示例中,创建的Logger的名称为com.Hyman.web。

名称表示"记录器"的层次结构。每个 。名称中的(点)表示层次结构中的一个级别。 (注意:这些级别与记录的消息的记录级别不同。)。名称为com.Hyman.web的Logger具有3个父母,名称如下:

""
"com"
"com.Hyman"

如果在上面的示例中创建的Logger上调用getParent(),则会获得名称为com.Hyman的Logger。如果我们在该Logger上调用getParent(),则会得到名称为com的Logger。层次结构的根是Logger,名称为空字符串("")。

需要注意的一件事是,我们需要在层次结构中创建"记录器",然后再将它们存在。因此,如果我们确实要创建Logger,如下所示:

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

...并调用getParent()方法,我们将获得名为"""的Logger。这样做的原因是,没有在层次结构中的" Logger"之间创建任何中间对象。我们需要执行以下操作来实例化层次结构中的所有Logger

Logger logger  = Logger.getLogger("");
Logger logger1 = Logger.getLogger("com");
Logger logger2 = Logger.getLogger("com.Hyman");
Logger logger3 = Logger.getLogger("com.Hyman.web");

现在,如果我们在logger3上调用getParent(),我们将获得名为com.HymanLogger。该Logger的父级被命名为com等。

记录器层次结构中的过滤器和处理程序

当消息传递给Logger时,如果Logger设置了Filter,则消息将通过Logger的Filter传递。 "过滤器"可以接受或者拒绝该消息。如果该消息被接受,则将该消息转发到在"记录器"上设置的"处理程序"。如果未设置"过滤器",则始终接受该消息。

如果消息被"过滤器"接受,则该消息还将转发到父"记录器"的"处理程序"。但是,当消息在层次结构中传递时,该消息不会通过父Logger的Filter传递。仅当消息直接传递到Logger时才要求Filter接受消息,而不是消息来自子Logger时才接受。

为了向我们展示这一效果,我将使用一些代码示例进行说明。

首先,这是一个在层次结构中创建3个记录器的示例。一个" ConsoleHandler"被分配给其中两个。根Logger默认情况下具有Handler,因此没有必要其中添加Handler。然后记录3条消息。通过层次结构中的每个"记录器"发送一条消息。这是代码:

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());

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

该代码的日志(控制台)中的输出为:

14-01-2012 10:32:41 java.util.logging.LogManager$RootLogger log
INFO: msg:
14-01-2012 10:32:42 logging.LoggingExamples main
INFO: msg: 1
14-01-2012 10:32:42 logging.LoggingExamples main
INFO: msg: 1
14-01-2012 10:32:42 logging.LoggingExamples main
INFO: msg: 1.2
14-01-2012 10:32:42 logging.LoggingExamples main
INFO: msg: 1.2
14-01-2012 10:32:42 logging.LoggingExamples main
INFO: msg: 1.2

请注意,第一条消息仅由根Logger记录一次。

第二条消息被记录两次:一次由1Logger记录,一次由根Logger`记录。

第三条消息被记录了三次:一次是通过1.2记录器记录,一次是通过1`记录器记录,一次是由根记录器记录。

现在,让我们尝试将过滤器添加到层次结构中的中间"记录器"中,该记录器名为" 1"。这是添加了Filter的代码:

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.setFilter(new Filter() {
    public boolean isLoggable(LogRecord record) {
    return false;
    }
    });

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

Filter拒绝在中间Logger上设置的所有消息时,记录的输出是这样的:

14-01-2012 11:33:21 java.util.logging.LogManager$RootLogger log
INFO: msg:
14-01-2012 11:33:21 logging.LoggingExamples main
INFO: msg: 1.2
14-01-2012 11:33:21 logging.LoggingExamples main
INFO: msg: 1.2
14-01-2012 11:33:21 logging.LoggingExamples main
INFO: msg: 1.2

请注意,第一条消息仍然记录一次,而第三条消息仍然记录三次,分别由层次结构中的每个"记录器"记录一次。

第二条消息,但是,发送到中间Logger的消息根本没有记录。在中间的Logger上设置的Filter总是返回false(表示它从不接受任何消息),过滤掉通过Logger记录的所有消息。因此,第二条消息永远不会被记录,也不会沿Logger层次结构传播。

但是请注意,消息从名为1.2的Logger沿层次结构传播到中间的Logger仍然记录,并且仍转发到根Logger。在中间的"记录器"上设置的"过滤器"不会触及传播的消息。

层次结构中记录器的日志级别

如本教程中其他地方提到的,我们可以分别为每个Logger设置要记录的消息的日志级别。如果Logger设置了一定的日志级别,那么所有重要性低于设置的日志级别的消息都将被忽略。另外,低于设置的日志级别的所有级别都不会沿" Logger"层次结构传播。这与"过滤器"的行为不同。

这是一个代码示例,其中显示了一个包含3个Logger的Logger层次结构,并且中间记录器(名为1)的最低日志级别设置为WARNING。

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

logger1  .setLevel(Level.WARNING);

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

这样的结果是,没有记录到中间记录器的消息的重要性不及WARNING,也没有消息向上传播。日志级别" INFO"的重要性不如"警告",因此记录到中间记录器的" INFO"消息将被忽略,并且不会传播到根记录器。

上面代码的另一个特殊结果是,传递给底部Logger(名为1.2)的INFO消息也将被忽略,并且不会传播。这样做的原因是,底部的" Logger"没有设置日志级别,因此继承了在" Logger"层次结构中其父级设置的级别。换句话说,底部的" Logger"继承了在中间的" Logger"上设置的日志级别。

这是上面的代码记录的输出:

14-01-2012 13:25:32 java.util.logging.LogManager$RootLogger log
INFO: msg:

实际上,只有通过根Logger直接记录的消息才被记录。

为了使所有" INFO"消息都可以从底部的" Logger"(命名为" 1.2")记录下来,即使中间的" Logger"的日志级别为" WARNING",我们也将以下内容添加到代码中(在大胆的):

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");

这段代码的结果是,现在记录在底部Logger(名为1.2)上的INFO消息,但仍未沿层次结构传播。是的,但是中间的"记录器"将其过滤掉了,因为中间的"记录器"的日志级别设置为"警告"。因此,该消息不会被中间的"记录器"记录,也不会沿层次结构传播。

底部和中间的"记录器"之间的虚线表示,只有"警告"或者更高重要性的消息才在层次结构中传播。

这是上面的代码记录的输出:

14-01-2012 13:30:27 java.util.logging.LogManager$RootLogger log
INFO: msg:
14-01-2012 13:30:27 logging.LoggingExamples main
INFO: msg: 1.2

记录到底部"记录器"的"信息"消息已记录,但未传播。

记录到中间Logger的INFO消息既不记录也不传播。

记录到根LoggerINFO消息被记录。

特定日志级别在"日志级别"中的文本中有更详细的介绍。这里的覆盖范围仅用于解释日志级别如何影响Logger层次结构中的消息传播。