--- old/jdk/src/java.base/share/classes/sun/util/logging/PlatformLogger.java 2015-11-09 17:14:55.000000000 -0800 +++ new/jdk/src/java.base/share/classes/sun/util/logging/PlatformLogger.java 2015-11-09 17:14:55.000000000 -0800 @@ -32,15 +32,13 @@ import java.io.StringWriter; import java.security.AccessController; import java.security.PrivilegedAction; -import java.time.Clock; -import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import jdk.internal.misc.JavaLangAccess; -import jdk.internal.misc.SharedSecrets; +import java.util.Optional; +import java.util.function.Predicate; /** * Platform logger provides an API for the JRE components to log @@ -539,44 +537,56 @@ throwable); } - // Returns the caller's class and method's name; best effort - // if cannot infer, return the logger's name. - private String getCallerInfo() { - String sourceClassName = null; - String sourceMethodName = null; + /* + * CallerFinder is a stateful predicate. + */ + static final class CallerFinder implements Predicate { + static final StackWalker WALKER = StackWalker.create(); - JavaLangAccess access = SharedSecrets.getJavaLangAccess(); - Throwable throwable = new Throwable(); - int depth = access.getStackTraceDepth(throwable); - - String logClassName = "sun.util.logging.PlatformLogger"; - boolean lookingForLogger = true; - for (int ix = 0; ix < depth; ix++) { - // Calling getStackTraceElement directly prevents the VM - // from paying the cost of building the entire stack frame. - StackTraceElement frame = - access.getStackTraceElement(throwable, ix); - String cname = frame.getClassName(); + /** + * Returns StackTraceElement of the caller's frame. + * @return StackTraceElement of the caller's frame. + */ + Optional get() { + return WALKER.walk(s -> s.filter(this).findFirst()); + } + + private boolean lookingForLogger = true; + + /** + * Returns true if we have found the caller's frame, false if the frame + * must be skipped. + * + * @param t The frame info. + * @return true if we have found the caller's frame, false if the frame + * must be skipped. + */ + @Override + public boolean test(StackWalker.StackFrame t) { + final String cname = t.getClassName(); + // We should skip all frames until we have found the logger, + // because these frames could be frames introduced by e.g. custom + // sub classes of Handler. if (lookingForLogger) { - // Skip all frames until we have found the first logger frame. - if (cname.equals(logClassName)) { - lookingForLogger = false; - } - } else { - if (!cname.equals(logClassName)) { - // We've found the relevant frame. - sourceClassName = cname; - sourceMethodName = frame.getMethodName(); - break; - } + lookingForLogger = !cname.equals("sun.util.logging.PlatformLogger"); + return false; } + // Once the logger is found - we should skip all frames that + // point to packages which contain artifacts that could be + // inserted between the logger and its caller. These could be + // logger wrappers from j.u.l or sun.util.logging (e.g. the + // PlatformLogger or artifacts between the PlatformLogger and + // the actual logger) or frames inserted by use of reflection + // and/or doPrivileged calls. + return !cname.startsWith("java.util.logging.") + && !cname.startsWith("sun.util.logging.") + && !cname.startsWith("java.security.AccessController"); } + } - if (sourceClassName != null) { - return sourceClassName + " " + sourceMethodName; - } else { - return name; - } + private String getCallerInfo() { + Optional frame = new CallerFinder().get(); + return frame.map(f -> f.getClassName() + " " + f.getMethodName()).orElse(name); } }