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()
    ,因为它是
    静态的。对我来说,使用
    static
    是一个好主意,因为实际实现是在JSF托管Bean中实现的
我怎样才能做到这一点

有人在这里问了一个类似的问题:,但它并没有为我提供一个解决方案

更新-1
  • 如果
    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

更新-2 如果我定义

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(包含方法调用的类的名称)有关