Log4j2-使用抽象类进行记录

时间:2018-07-24 10:51:49

标签: java inheritance logging abstract-class log4j2

我有以下代码:

MySuperClass

package com.mypackage;

public abstract class MySuperClass {
    private static final Logger LOGGER = LogManager.getLogger();

    protected void demoLog() {
        LOGGER.debug("My message")
    }
}

MyClass

package com.mypackage;

public class MyClass extends MySuperClass {

    public void executeLog() {
        demoLog();
    }
}

执行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被多个类扩展
  • 我无法通过从Class调用LogManager.getLogger()来传递getClass()作为MySuperClass的参数,因为它是static。对我来说,使用static是个好主意,因为实际的实现是在JSF托管Bean中进行的。

我该如何实现?

这里有一个类似的问题:Java Logging With Abstract Classes,但这并没有为我提供解决方案。

更新-1

  • 如果将Logger中的MySuperClass定义为private final Logger logger = LogManager.getLogger(getClass());,则发射器仍为com.mypackage.MySuperClass
  • 如果我定义

    protected abstract Logger getLogger();
    
    MySuperClass

    并将其实现为

    private final Logger logger = LogManager.getLogger(getClass());
    
    @Override
    protected Logger getLogger() {
        return logger;
    }
    

    MyClass中的发射器是相同的,即com.mypackage.MySuperClass

更新-2

如果我定义

protected abstract Logger getLogger();
MySuperClass

并将其实现为

private final Logger logger = LogManager.getLogger(MyClass.class);

@Override
protected Logger getLogger() {
    return logger;
}

MyClass中的发射器是相同的,即com.mypackage.MySuperClass

2 个答案:

答案 0 :(得分:1)

一种实现方法是将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;
    }
}

EDIT :我没有看到您提供的链接,现在我注意到我的回答是this answer的类似物,据我所知-这不是您要寻找的解决方案。


实际答案

好的,所以这个问题的意思(以及“发射器”的含义)是Log4j2 "class" conversion pattern(使用%C%class获得)而不是{{1 }}相关的模式(使用Logger%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>

使用此配置运行我的代码时,得到的输出是:

Logger=com.mypackage.MySuperClass | Class: com.mypackage.MySuperClass | My message

如您所见,我的代码中使用了适当的Logger=com.mypackage.MyClass | Class: com.mypackage.MySuperClass | My message ,但Logger保持不变。

现在,这是%class conversion pattern的摘录:

  

输出发出以下信息的调用方的全限定类名:   记录请求。 [...]

     

生成调用方的类名(位置信息)是一种   昂贵的操作,可能会影响性能。谨慎使用。

如您所见,这是从Class方法的调用站点的堆栈跟踪中检索的类名。

最后,您不能更改此特定值,因为实际上发生了呼叫Logger.debug。但是,您可以要做的是将MySuperClass转换模式替换为%class转换模式以获得预期的结果。

答案 1 :(得分:-1)

不要使其变为静态。记录器在“相同密钥”之间共享,因此它们将在同一类的实例之间共享。