Java Log4j2-使用抽象类进行日志记录
我有以下代码: 我的超级阶级 类名 当执行Java Log4j2-使用抽象类进行日志记录,java,inheritance,logging,abstract-class,log4j2,Java,Inheritance,Logging,Abstract Class,Log4j2,我有以下代码: 我的超级阶级 类名 当执行com.mypackage.MyClass#executeLog方法时,它会打印: 2018-07-24 10:39:04,964 : DEBUG : : com.mypackage.MySuperClass : demoLog : My message 在日志消息中,发射器是com.mypackage.MySuperClass,但我希望将com.mypackage.MyClass作为发射器 com.mypackage.MySuperClass由多个
com.mypackage.MyClass#executeLog
方法时,它会打印:
2018-07-24 10:39:04,964 : DEBUG : : com.mypackage.MySuperClass : demoLog : My message
在日志消息中,发射器是com.mypackage.MySuperClass
,但我希望将com.mypackage.MyClass
作为发射器
由多个类扩展com.mypackage.MySuperClass
- 我无法通过调用
中的MySuperClass
将getClass()
作为参数传递给Class
,因为它是LogManager.getLogger()
静态的。对我来说,使用
是一个好主意,因为实际实现是在JSF托管Bean中实现的static
- 如果
中的MySuperClass
定义为Logger
private final Logger Logger=LogManager.getLogger(getClass())代码>,发射器仍然是
com.mypackage.MySuperClass
- 如果我定义
protected abstract Logger getLogger();
在protected abstract Logger getLogger();
中,将其实现为MySuperClass
private final Logger logger = LogManager.getLogger(getClass()); @Override protected Logger getLogger() { return logger; }
在private final Logger logger = LogManager.getLogger(MyClass.class); @Override protected Logger getLogger() { return logger; }
中,发射器是相同的,即MyClass
com.mypackage.MySuperClass
protected abstract Logger getLogger();
protected abstract Logger getLogger();
在MySuperClass
中,将其实现为
private final Logger logger = LogManager.getLogger(getClass());
@Override
protected Logger getLogger() {
return logger;
}
private final Logger logger = LogManager.getLogger(MyClass.class);
@Override
protected Logger getLogger() {
return logger;
}
在
MyClass
中,发射器是相同的,即com.mypackage.MySuperClass
一种方法是将LOGGER
常量迁移到所有叶子类,然后通过受保护的抽象方法访问它,如下所示:
public abstract class MySuperClass {
protected void demoLog() {
logger().debug("My message");
}
protected abstract Logger logger();
}
public class MyClass extends MySuperClass {
private static final Logger LOGGER = LogManager.getLogger();
public void executeLog() {
demoLog();
}
@Override
protected Logger logger() {
return LOGGER;
}
}
编辑:我没有看你提供的链接,现在我看了,我注意到我的答案是类似的,所以-据我所知-这不是你想要的解决方案
实际答案 好的,那么这个问题是关于(以及你所说的“发射器”)的(使用
%C
或%class
获得),而不是记录器相关模式(使用%C
或%Logger
获得)
考虑与您的示例相关的log4j2.xml
配置文件:
<Appenders>
<Console name="loggerVsClassAppender" target="SYSTEM_OUT">
<PatternLayout pattern="Logger=%logger | Class: %class | %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="com.mypackage" level="trace">
<AppenderRef ref="loggerVsClassAppender"/>
</Logger>
</Loggers>
使用此配置运行my代码时,得到的输出为:
Logger=com.mypackage.MySuperClass | Class: com.mypackage.MySuperClass | My message
Logger=com.mypackage.MyClass | Class: com.mypackage.MySuperClass | My message
如您所见,在我的代码中使用了适当的记录器
,但类
保持不变
现在,这里有一段摘录自以下描述:
输出发出
日志记录请求。[……]
生成调用方的类名(位置信息)是一个简单的过程
操作成本高,可能会影响性能。小心使用
如您所见,这是从Logger.debug
方法调用站点的堆栈跟踪中检索到的类名
总之,不能更改此特定值,因为调用实际上发生在MySuperClass
中。但是,您所能做的是将%class
转换模式替换为%logger
转换模式,以获得预期的结果。不要将其设置为静态。记录器在“同一密钥”之间共享,因此它们将在同一类的实例之间共享。确实要这样做吗?记录器通常与发生日志记录的类相关联。在这里,您执行登录MySuperClass
,因此将其登录到MyClass
下可能会产生误导。我不明白您链接的答案为什么不正确,这似乎是完成此类事情的正常方式。对我来说,使用static似乎是个坏主意(但使用JSF-fwiw也是如此)。这种方法有什么特别的原因吗?资源?@NathanHughes请检查我的更新您是否可以将MyClass中的记录器定义为LogManager.getLogger(MyClass.class)
?您好,谢谢您的回复,不过请检查我的更新。@TapasBose谢谢!我更新了我的答案-我希望它对你有所帮助。@TomaszLinkowski你的答案是反向的。记录器的名称是在实例化记录器时计算的。通常,它是记录器所在的类的名称。另一方面,该类将是调用logger方法的类的名称。它将根据调用的类而变化。因此,如果要始终打印调用log方法的类的名称,则必须将布局配置为打印该类,而不是日志记录器。@rgoers您的描述是正确的,并且我非常确定我的描述是正确的:)也许您没有足够仔细地阅读该问题,或者您理解了“调用logger方法的类”不同地OP抱怨说执行MyClass.executeLog
->MySuperClass.demoLog
->MySuperClass.LOGGER.debug
打印MySuperClass
。即使将最后一部分更改为MySuperClass.logger().debug
(其中现在logger
=MyClass
),OP仍然可以看到MySuperClass
(因为MySuperClass
中调用了debug
)。因此,我的结论是,他使用%class
而不是%logger
@TomaszLinkowski,将超类中logger
的实例定义为:私有最终logger logger=LogManager.getLogger(getClass())
并将模式布局从%c
更改为%c
,成功了。感谢您的指针。将记录器设为静态与问题无关。@rgoers ofc它作为非静态上下文将允许您this.getClass()
在结果中为每个继承类创建一个记录器实例。此外,正如您所看到的,公认的解决方案是基于使记录器成为非静态的(参见注释)。公认的答案与记录器是静态的无关。这与格式是使用%c(记录器的名称)还是使用%c(包含方法调用的类的名称)有关