Usage

静态 Logger 与非静态 Logger

与 Java 中的任何变量一样,Logger 可以声明为静态变量或类成员变量。但是,在选择将 Logger 声明为静态与非静态时,需要考虑一些因素。通常,最好将 Loggers 声明为静态。

记录 Logger 名称与类名称

创建 Logger 时,将指定 Logger 的 Logger 名称。调用日志方法时,日志事件中的类名称值将反映调用该日志方法的类的名称,该名称不必与创建 Logger 的类相同。以下示例对此进行了说明。

Base Class 创建一个静态 Logger 和一个初始化为该 Logger 的 logger 变量。它具有一种执行日志记录的方法,但提供了对两个 Logger 的访问权,一个是静态的,一个可以被覆盖。

package org.apache.logging;

  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.Logger;
  import org.apache.logging.log4j.Marker;

  /**
  *
  */
  public abstract class Parent {

      // The name of this Logger will be "org.apache.logging.Parent"
      protected static final Logger parentLogger = LogManager.getLogger();

      private Logger logger = parentLogger;

      protected Logger getLogger() {
          return logger;
      }

      protected void setLogger(Logger logger) {
          this.logger = logger;
      }

      public void log(Marker marker) {
          logger.debug(marker,"Parent log message");
      }
  }

此类扩展了基础类。它提供了自己的 Logger,并具有三种方法,一种使用此类中的 Logger,一种使用 Base Class 中的静态 Logger,以及一种可以将 Logger 设置为父项或子项的方法。

package org.apache.logging;

  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.Logger;
  import org.apache.logging.log4j.Marker;

  /**
  *
  */
  public class Child extends Parent {

      // The name of this Logge will be "org.apache.logging.Child"
      public Logger childLogger = LogManager.getLogger();

      public void childLog(Marker marker) {
          childLogger.debug(marker,"Child logger message");
      }

      public void logFromChild(Marker marker) {
          getLogger().debug(marker,"Log message from Child");
      }

      public void parentLog(Marker marker) {
          parentLogger.debug(marker,"Parent logger, message from Child");
      }
  }

该应用程序将练习所有记录方法四次。Base Class 中的前两次 Logger 设置为静态 Logger。第二次将 Base Class 中的 Logger 设置为使用子类中的 Logger。在每个方法的第一次和第三次调用中,将传递一个空标记。在第二个和第四个中,传递了一个名为“ CLASS”的标记。

package org.apache.logging;

  import org.apache.logging.log4j.Marker;
  import org.apache.logging.log4j.MarkerManager;

  public class App {

      public static void main( String[] args ) {
          Marker marker = MarkerManager.getMarker("CLASS");
          Child child = new Child();

          System.out.println("------- Parent Logger ----------");
          child.log(null);
          child.log(marker);
          child.logFromChild(null);
          child.logFromChild(marker);
          child.parentLog(null);
          child.parentLog(marker);

          child.setLogger(child.childLogger);

          System.out.println("------- Parent Logger set to Child Logger ----------");
          child.log(null);
          child.log(marker);
          child.logFromChild(null);
          child.logFromChild(marker);
      }
  }

该配置利用 Log4j 的功能,可以基于日志事件的属性选择模式。在这种情况下,当使用 CLASS 标记时使用%C,即类名模式,当不使用 CLASS 标记时,使用%c,即 Logger 名。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout>
        <MarkerPatternSelector defaultPattern="%sn. %msg: Logger=%logger%n">
          <PatternMatch key="CLASS" pattern="%sn. %msg: Class=%class%n"/>
        </MarkerPatternSelector>
      </PatternLayout>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="TRACE">
      <AppenderRef ref="Console" />
    </Root>
  </Loggers>
</Configuration>

以下输出说明了在模式中使用 Logger 名称和 Class 名称之间的区别。所有奇数编号的项目均打印 Logger 的名称(%c),而所有偶数编号的项目均打印调用日志记录方法的类的名称(%C)。下表中结果描述中的数字与输出中显示的相应数字匹配。

------- Parent Logger ----------
  1. Parent log message: Logger=org.apache.logging.Parent
  2. Parent log message: Class=org.apache.logging.Parent
  3. Log message from Child: Logger=org.apache.logging.Parent
  4. Log message from Child: Class=org.apache.logging.Child
  5. Parent logger, message from Child: Logger=org.apache.logging.Parent
  6. Parent logger, message from Child: Class=org.apache.logging.Child
  ------- Parent Logger set to Child Logger ----------
  7. Parent log message: Logger=org.apache.logging.Child
  8. Parent log message: Class=org.apache.logging.Parent
  9. Log message from Child: Logger=org.apache.logging.Child
  10. Log message from Child: Class=org.apache.logging.Child

在上面的示例中,声明了两个 Logger。一种是静态的,一种是非静态的。查看结果时,很明显,无论 Logger 如何声明,结果都是完全相同的。Logger 的名称将始终源自创建 Logger 的类,并且每个日志事件中的类名称将始终反映调用记录方法的类。

应该注意的是,打印位置信息(类名,方法名和行号)会大大降低性能。如果方法名称和行号不重要,通常最好确保每个类都有自己的 Logger,以便 Logger 名称准确反映执行记录的类。

首页