我有一个子类和一个超类。在超类中,我有一个记录某些东西的方法。当我创建子类的实例时,记录器为超类创建日志消息。为什么会发生这种情况?
代码示例:
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
正如您所看到的,该类的名称已正确打印,但在日志消息中未正确显示。
答案 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解释了为什么会发生这种情况,我会尝试解释一种解决方法。
如果您希望查看确切的类,在哪里调用方法,我建议您使用log4j或slf4j。如果您确实需要使用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
对象现在正在子类中而不是在超类内实例化。