Stefan S.
Stefan S.

Reputation: 4103

Configure Logger Programmatically

I want to configure my java.util.logging.Logger programmatically. According to the Oracle Docs, it seems possible.

However this example shows something is wrong here:

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!");
}

If you run the code, you'll see both messages. However if you remove logger = null; or System.gc(); you'll only see the correct second one, which proves the garbage collector just removes the configured logger leaving Logger.getLogger(String) with creating a new (default) one.

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

So how do I define a logger programmatically?

Upvotes: 4

Views: 2089

Answers (2)

jmehrens
jmehrens

Reputation: 11035

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

In releases prior to JDK6u18 the LogManager held strong reference to the logger. After that patch, the java.util.logging.Logger.getLogger() method points the reader towards holding a strong reference:

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.

A common idiom is to use:

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

The reason you define the CLASS_NAME too is that you'll use it for the log tracing methods or the logp methods

Also, tools like FindBugs will detect this lost logger pattern as:

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

Upvotes: 2

Luciano van der Veekens
Luciano van der Veekens

Reputation: 6577

The Javadoc for Logger#getLogger references your problem:

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.

In turn Logger#getLogger calls LogManager#addLogger and its documentation also encourages you to hold a reference:

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.

Upvotes: 1

Related Questions