静态Logger VS 非静态Logger
与Java中的任何变量一样,Logger可以声明为静态变量或类成员变量。 但是,在选择将Logger指定为静态和非静态时,需要考虑几个因素。 通常,最好将Loggers声明为静态。
- 使用默认的ContextSelector,ClassLoaderContextSelector时,实例化新的Logger是一项相当昂贵的操作。创建Logger时,ClassLoaderContextSelector将找到与Logger关联的ClassLoader,并将Logger添加到与该ClassLoader关联的LoggerContext。
- 创建Logger后,除非删除与其关联的LoggerContext,否则不会删除Logger。 通常,删除Logger只会在应用程序关闭或取消部署时发生。 每次使用相同的Logger名称调用getLogger都将返回相同的Logger实例。 因此,静态或非静态Logger之间的差异非常小。
- 静态和非静态Logger之间没有行为差异。 两者都将在创建时分配Logger名称,这通常是与其关联的类的名称。 有关更多信息,请参阅下面有关Logger名称与类名称讨论。
Logger名称VS类名称
创建Logger时需要指定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");
}
}
Child类继承一个父类。 它提供了自己的记录器并且有三个日志记录的方法,一个使用此类中的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 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");
}
}
该应用程序执行四次日志记录方法。 child.log和child.logFromChild前两次日志输出使用的是父类中静态Logger。 child.log和child.logFromChild后两次输出设置为使用子类中的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根据日志事件的属性选择模式的能力。在这种情况下,类名模式%C在CLASS标记存在时使用类名称,而%c在CLASS标记不存在时使用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名称和类名称之间的区别。 所有奇数项都打印记Logger名称(%c),而所有偶数项打印调用记录方法的类的名称(%C)。 以下列表中结果输出显示数字与描述相匹配。
- 使用父类静态Logger在执行日志记录。 记录器名称与父类的名称匹配。
- 使用具有类名称模式下使用父类的静态记录器行日志记录。 虽然该方法是针对Child实例调用的,但它是在Parent中实现的,所以会输出父类名称。
- 使用父类中的Logger在Child中执行日志记录,因此父类的名称将打印为Logger名称。
- 使用父类中的日志程序在子类中执行日志记录。由于调用日志记录方法的方法位于子类中,因此出现子类名。
- 使用父类中的静态Logger在Child中执行日志记录,因此父类的名称将打印为Logger名称。
- 使用父类中的静态Logger在Child中执行日志记录。 由于调用日志记录方法的方法在Child中,因为子类名打印为Logger名称。
- 使用Child的Logger执行父类的日志记录方法。 记录器名称与子名称匹配,因此将打印子类名称。
- 使用Child的Logger执行父类中日志记录方法。 虽然该方法是针对Child实例调用的,但它是在Parent中实现的,因使用Child的Logge执行此它显示父类类名。
- 使用Child的Logger执行Child中日志记录方法,因此子类的名称将作为Logger名称打印。
- 使用Child的Logger执行Child中日志记录方法。 由于调用日志记录的方法在Child中,因为它是出现的子类类名。
------- 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,以便记录器名称准确反映执行日志记录的类。
- log4j2使用手册(中文)第一章 介绍
- log4j2使用手册(中文)第二章 架构
- log4j2使用手册(中文)第三章 Log4j 1.x 迁移至Log4j 2
- log4j2使用手册(中文)第四章 API
- log4j2使用手册(中文)第五章 Configuration
- log4j2使用手册(中文)第六章 使用
- log4j2使用手册(中文)第七章 Web Applications and JSPs
- log4j2使用手册(中文)第八章 Lookups
网友评论