如何获取子类的Logger?

时间:2013-03-15 17:43:32

标签: java java.util.logging

我有一个子类和一个超类。在超类中,我有一个记录某些东西的方法。当我创建子类的实例时,记录器为超类创建日志消息。为什么会发生这种情况?

代码示例:

SuperClass.java

import java.util.logging.Level;
import java.util.logging.Logger;

public abstract class SuperClass {
    public void logAndPrintClass(){
        String name = this.getClass().getName();
        System.out.println(name);
        Logger logger = Logger.getLogger(name);
        logger.log(Level.INFO, "Logmessage");
    }
}

SubClass.java

public class SubClass extends SuperClass {
}

TestLogBubClass.java

public class TestLogBubClass {

    public static void main(String[] args){
        SuperClass obj = new SubClass();
        obj.logAndPrintClass();
    }
}

输出:

SubClass
Mar 15, 2013 6:30:04 PM SuperClass logAndPrintClass
INFO: Logmessage

正如您所看到的,该类的名称已正确打印,但在日志消息中未正确显示。

4 个答案:

答案 0 :(得分:5)

这个原因出现在LogRecord的JavaDoc中:

  

请注意,如果客户端应用程序未指定显式的源方法名称和源类名,则LogRecord类将在首次访问它们时(通过调用getSourceMethodName或getSourceClassName)通过分析调用堆栈自动推断它们

在这种情况下,调用堆栈以SuperClass定义的方法结束,因此LogRecord假定它是被调用的类。如果要查看此操作,请执行以下代码:

public class Example {

    public static class Superclass {
        public void foo() {
            new Exception().printStackTrace();
        }
    }

    public static class Subclass extends Superclass {
        // nothing here
    }

    public static void main(String[] argv)
    throws Exception
    {
        Superclass s = new Subclass();
        s.foo();
    }
}

编辑:我不使用j.u.l,但希望有一种简单的方法来配置输出(就像所有其他记录器实现提供的那样)。您似乎必须实现自己的Formatter类,并使用java.util.logging.ConsoleHandler.formatter属性指定它。

我建议尽可能切换到SLF4J。您可以将所有现有的j.u.l代码通过SLF4J桥接到一个实际的记录器,使您可以更好地控制其输出(如Log4J或Logback)。

答案 1 :(得分:1)

这个java.util.logging代码很奇怪.. Logging不使用name,而是尝试查找源类本身(然后记录)。 请查看课程private void inferCaller()中的java.util.logging.LogRecord方法。

答案 2 :(得分:1)

@Parsifal解释了为什么会发生这种情况,我会尝试解释一种解决方法。

如果您希望查看确切的类,在哪里调用方法,我建议您使用log4jslf4j。如果您确实需要使用java.util.Logger,请查看jul-to-slf4j

我已尝试使用相同的类输入,在我的标准输出中输入如下所示:

  

子类

     

2013年3月15日下午8:39:44 SuperClass logAndPrintClass

     

信息:Logmessage

     

20:39:44,478 INFO子类:12 - Logmessage

在日志文件中只有:

  

20:39:44,478 INFO子类:12 - Logmessage

它可能看起来不太好,但在某些情况下,这可能是合适的解决方法。

答案 3 :(得分:0)

我想我有一个解决方法,即使我无法提供完整的解释。

logAndPrintClass中仅通过super来电覆盖SubClass {/ 1}}:

class SubClass extends SuperClass {
    protected void logAndPrintClass(){ super.logAndPrintClass(); }
}

我仍然得到相同的输出。

SubClass
Mar 15, 2013 11:22:10 AM SuperClass logAndPrintClass
INFO: Logmessage

然后我只是将方法体复制到子类中:

class SubClass extends SuperClass {
    protected void logAndPrintClass(){
        String name = this.getClass().getName();
        System.out.println(name);
        Logger logger = Logger.getLogger(name);
        logger.log(Level.INFO, "Logmessage");
    }
}

然后我得到了不同的输出:

SubClass
Mar 15, 2013 11:23:31 AM SubClass logAndPrintClass

我不知道为什么会这样,但我似乎发现的唯一区别是Logger对象现在正在子类中而不是在超类内实例化。