FULL PRODUCT VERSION :
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
java version "1.7.0_95"
Java(TM) SE Runtime Environment (build 1.7.0_95-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.95-b01, mixed mode)
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b05)
Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01, mixed mode)
java version "1.5.0_17"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_17-b03)
Java HotSpot(TM) Client VM (build 1.5.0_17-b03, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
LogRecord.inferCaller doesn't seem to handle subclasses of java.util.logging.Logger correctly between JDK 5 through 8. The caller always seems to be inferred as 'java.util.logging.LogManager$RootLogger log'. This seems to be fixed in JDK9. I have not tested JDK 1.4.
If any handler is installed on the root logger then source class and source method names are incorrect.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Install a handler on the root logger. Call any on the non-log precise methods.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
java.util.logging.LogManager$RootLogger methods should be skipped just like all other logger methods. It would be nice if this was backported to JDK8. If that is not possible the least that should be done ensure this is covered by a unit test.
ACTUAL -
java.util.logging.LogManager$RootLogger log is reported as the source class and source method name.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Found {
public static void main(String[] arg) {
fooSelf(Logger.getLogger(""));
fooSelf(Logger.getLogger("global"));
fooSelf(Logger.getLogger("test"));
fooRoot(Logger.getLogger(""));
fooRoot(Logger.getLogger("global"));
fooRoot(Logger.getLogger("test"));
}
private static void fooSelf(Logger log) {
boolean b = log.getUseParentHandlers();
log.setUseParentHandlers(false);
Handler[] handlers = log.getHandlers();
for (Handler old : handlers) {
log.removeHandler(old);
}
Handler h = new ConsoleHandler();
log.addHandler(h);
log.log(Level.SEVERE, log.getName());
log.removeHandler(h);
for (Handler old : handlers) {
log.addHandler(old);
}
log.setUseParentHandlers(b);
}
private static void fooRoot(Logger log) {
final Logger root = Logger.getLogger("");
boolean b = log.getUseParentHandlers();
log.setUseParentHandlers(true);
boolean found = false;
Handler[] handlers = root.getHandlers();
for (Handler old : handlers) {
if (old.getClass() == ConsoleHandler.class) {
found = true;
break;
}
}
if (!found) {
root.addHandler(new ConsoleHandler());
}
log.log(Level.SEVERE, log.getName());
if (!found) {
for (Handler old : handlers) {
if (old.getClass() == ConsoleHandler.class) {
root.removeHandler(old);
break;
}
}
}
log.setUseParentHandlers(b);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Install a filter on the handler that implements the stack-walking code and change the log record source class and source name (not thread safe).