以编程方式配置记录器

Configure Logger Programmatically

我想以编程方式配置我的 java.util.logging.Logger。根据Oracle Docs,好像可以。

但是这个例子表明这里有问题:

public static void main(String[] args) {
    Logger logger = Logger.getLogger("org.acme.project");
    logger.setLevel(Level.SEVERE);
    logger = null;

    System.gc();

    logger = Logger.getLogger("org.acme.project");
    logger.warning("You shouldn't see this warning!");
    logger.severe("But this error!");
}

如果您 运行 代码,您将看到这两条消息。但是,如果您删除 logger = null;System.gc();,您只会看到正确的第二个,这证明垃圾收集器只是删除了配置的记录器,而留下 Logger.getLogger(String) 并创建了一个新的(默认)记录器。

为了 "solve" 这个,我可以在某处保留对那个特定记录器的引用,但我认为这不是个好主意。

那么如何以编程方式定义记录器?

To "solve" this, I could just hold a reference to that particular logger somewhere, but I don't think that's a good idea.

JDK6u18 the LogManager held strong reference to the logger. After that patch, the java.util.logging.Logger.getLogger() 方法之前的版本中指向 reader 持有强引用:

Note: The LogManager may only retain a weak reference to the newly created Logger. It is important to understand that a previously created Logger with the given name may be garbage collected at any time if there is no strong reference to the Logger. In particular, this means that two back-to-back calls like getLogger("MyLogger").log(...) may use different Logger objects named "MyLogger" if there is no strong reference to the Logger named "MyLogger" elsewhere in the program.

一个常见的习语是使用:

private static final String CLASS_NAME = Foo.class.getName();
private static final Logger logger = Logger.getLogger(CLASS_NAME);

您也定义 CLASS_NAME 的原因是您会将其用于日志跟踪方法或 logp 方法

此外,像 FindBugs 这样的工具会检测到这种丢失的记录器模式:

LG: Potential lost logger changes due to weak reference in OpenJDK (LG_LOST_LOGGER_DUE_TO_WEAK_REFERENCE)

Logger#getLogger 的 Javadoc 引用了您的问题:

https://docs.oracle.com/javase/7/docs/api/java/util/logging/Logger.html#getLogger%28java.lang.String%29

Note: The LogManager may only retain a weak reference to the newly created Logger. It is important to understand that a previously created Logger with the given name may be garbage collected at any time if there is no strong reference to the Logger. In particular, this means that two back-to-back calls like getLogger("MyLogger").log(...) may use different Logger objects named "MyLogger" if there is no strong reference to the Logger named "MyLogger" elsewhere in the program.

反过来 Logger#getLogger 调用 LogManager#addLogger 并且其文档也鼓励您持有参考:

https://docs.oracle.com/javase/7/docs/api/java/util/logging/LogManager.html#addLogger%28java.util.logging.Logger%29

The application should retain its own reference to the Logger object to avoid it being garbage collected. The LogManager may only retain a weak reference.