You must always hold a strong non-local reference to loggers that you are modifying. Otherwise your logger can be garbage collected along with your newly attached handler.
As explained in the Java Logging Overview:
Loggers keep track of their parent loggers in the logging namespace. A logger's parent is its nearest extant ancestor in the logging namespace. The root Logger (named "") has no parent.
You are attaching a handler to the GLOBAL_LOGGER_NAME
. The parent of the global logger is the root logger. Normally, the global logger has no children therefore, you won't see any output unless you are directly writing to the global logger. My advice would be to forget about using the global logger. Instead focus on modifying the output format of the root logger and have your application code create named loggers.
You don't have to create a custom handler. Instead create a custom formatter and install it on the ConsoleHandler attached to the root logger.
Here is an example program:
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class ModifyRoot {
private static final Logger[] PINNED_LOGGERS;
static {
//Assuming the default config file.
PINNED_LOGGERS = new Logger[]{
Logger.getLogger(""),
Logger.getLogger(ModifyRoot.class.getName())
};
for (Logger l : PINNED_LOGGERS) {
for (Handler h : l.getHandlers()) {
if (h instanceof ConsoleHandler) {
h.setFormatter(new DynamicFormatter());
h.setLevel(Level.ALL);
}
}
}
//Safe because it is already pinned.
Logger.getLogger(ModifyRoot.class.getName()).setLevel(Level.ALL);
}
private static class DynamicFormatter extends java.util.logging.Formatter {
@Override
public String format(LogRecord record) {
if (isJumpSite(record)) {
return record.getSourceClassName() + '.'
+ record.getSourceMethodName() + ' '
+ formatMessage(record) + System.lineSeparator();
} else {
return formatMessage(record) + System.lineSeparator();
}
}
private boolean isJumpSite(LogRecord record) {
//Check the raw message not the formatted message.
final String msg = String.valueOf(record.getMessage());
return msg.startsWith("ENTRY") || msg.startsWith("RETURN")
|| msg.startsWith("THROW");
}
}
//========
private static final String CLASS_NAME = ModifyRoot.class.getName();
private static final Logger logger = Logger.getLogger(CLASS_NAME);
public static void main(String[] args) {
logger.entering(CLASS_NAME, "main");
logger.info("Hello World!");
logger.exiting(CLASS_NAME, "main");
}
}
Which outputs:
ModifyRoot.main ENTRY
Hello World!
ModifyRoot.main RETURN
You should really consider configuring your loggers using the java.util.logging.config.file system property and creating your own logging.properties
file.