< prev index next >

jdk/src/java.logging/share/classes/java/util/logging/LogRecord.java

Print this page

        

@@ -28,13 +28,11 @@
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.io.*;
 import java.time.Clock;
-
-import jdk.internal.misc.JavaLangAccess;
-import jdk.internal.misc.SharedSecrets;
+import java.util.function.Predicate;
 
 /**
  * LogRecord objects are used to pass logging requests between
  * the logging framework and individual log Handlers.
  * <p>

@@ -637,45 +635,64 @@
     }
 
     // Private method to infer the caller's class and method names
     private void inferCaller() {
         needToInferCaller = false;
-        JavaLangAccess access = SharedSecrets.getJavaLangAccess();
-        Throwable throwable = new Throwable();
-        int depth = access.getStackTraceDepth(throwable);
-
-        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();
-            boolean isLoggerImpl = isLoggerImplFrame(cname);
-            if (lookingForLogger) {
                 // Skip all frames until we have found the first logger frame.
-                if (isLoggerImpl) {
-                    lookingForLogger = false;
-                }
-            } else {
-                if (!isLoggerImpl) {
-                    // skip reflection call
-                    if (!cname.startsWith("java.lang.reflect.") && !cname.startsWith("sun.reflect.")) {
-                       // We've found the relevant frame.
-                       setSourceClassName(cname);
-                       setSourceMethodName(frame.getMethodName());
-                       return;
-                    }
-                }
-            }
-        }
+        Optional<StackWalker.StackFrame> frame = new CallerFinder().get();
+        frame.ifPresent(f -> {
+            setSourceClassName(f.getClassName());
+            setSourceMethodName(f.getMethodName());
+        });
+
         // We haven't found a suitable frame, so just punt.  This is
         // OK as we are only committed to making a "best effort" here.
     }
 
-    private boolean isLoggerImplFrame(String cname) {
-        // the log record could be created for a platform logger
-        return (cname.equals("java.util.logging.Logger") ||
-                cname.startsWith("java.util.logging.LoggingProxyImpl") ||
-                cname.startsWith("sun.util.logging."));
+    /*
+     * CallerFinder is a stateful predicate.
+     */
+    static final class CallerFinder implements Predicate<StackWalker.StackFrame> {
+        static final StackWalker WALKER = StackWalker.getInstance();
+
+        /**
+         * Returns StackFrame of the caller's frame.
+         * @return StackFrame of the caller's frame.
+         */
+        Optional<StackWalker.StackFrame> 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) {
+                lookingForLogger = !cname.equals("java.util.logging.Logger") &&
+                        !cname.startsWith("java.util.logging.LoggingProxyImpl") &&
+                        !cname.startsWith("sun.util.logging.");
+                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.uti.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");
+        }
     }
 }
< prev index next >