13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.util.logging;
27 import java.time.Instant;
28 import java.util.*;
29 import java.util.concurrent.atomic.AtomicInteger;
30 import java.util.concurrent.atomic.AtomicLong;
31 import java.io.*;
32 import java.time.Clock;
33
34 import jdk.internal.misc.JavaLangAccess;
35 import jdk.internal.misc.SharedSecrets;
36 import static jdk.internal.logger.SimpleConsoleLogger.skipLoggingFrame;
37
38 /**
39 * LogRecord objects are used to pass logging requests between
40 * the logging framework and individual log Handlers.
41 * <p>
42 * When a LogRecord is passed into the logging framework it
43 * logically belongs to the framework and should no longer be
44 * used or updated by the client application.
45 * <p>
46 * Note that if the client application has not specified an
47 * explicit source method name and source class name, then the
48 * LogRecord class will infer them automatically when they are
49 * first accessed (due to a call on getSourceMethodName or
50 * getSourceClassName) by analyzing the call stack. Therefore,
51 * if a logging Handler wants to pass off a LogRecord to another
52 * thread, or to transmit it over RMI, and if it wishes to subsequently
53 * obtain method name or class name information it should call
54 * one of getSourceClassName or getSourceMethodName to force
55 * the values to be filled in.
644 // by which LogRecord will infer the source class name and source method name
645 // when analyzing the call stack.
646 // <p>
647 // The system property {@code jdk.logger.packages} can define a comma separated
648 // list of strings corresponding to additional package name prefixes that
649 // should be ignored when trying to infer the source caller class name.
650 // Those stack frames whose {@linkplain StackTraceElement#getClassName()
651 // declaring class name} start with one such prefix will be ignored.
652 // <p>
653 // This is primarily useful when providing utility logging classes wrapping
654 // a logger instance, as it makes it possible to instruct LogRecord to skip
655 // those utility frames when inferring the caller source class name.
656 // <p>
657 // The {@code jdk.logger.packages} system property is consulted only once.
658 // <p>
659 // This property is not standard, implementation specific, and yet
660 // undocumented (and thus subject to changes without notice).
661 //
662 private void inferCaller() {
663 needToInferCaller = false;
664 JavaLangAccess access = SharedSecrets.getJavaLangAccess();
665 Throwable throwable = new Throwable();
666 int depth = access.getStackTraceDepth(throwable);
667
668 boolean lookingForLogger = true;
669 for (int ix = 0; ix < depth; ix++) {
670 // Calling getStackTraceElement directly prevents the VM
671 // from paying the cost of building the entire stack frame.
672 StackTraceElement frame =
673 access.getStackTraceElement(throwable, ix);
674 String cname = frame.getClassName();
675 boolean isLoggerImpl = isLoggerImplFrame(cname);
676 if (lookingForLogger) {
677 // Skip all frames until we have found the first logger frame.
678 if (isLoggerImpl) {
679 lookingForLogger = false;
680 }
681 } else {
682 if (!isLoggerImpl) {
683 // skip logging/logger infrastructure and reflection calls
684 if (!skipLoggingFrame(cname)) {
685 // We've found the relevant frame.
686 setSourceClassName(cname);
687 setSourceMethodName(frame.getMethodName());
688 return;
689 }
690 }
691 }
692 }
693 // We haven't found a suitable frame, so just punt. This is
694 // OK as we are only committed to making a "best effort" here.
695 }
696
697 private boolean isLoggerImplFrame(String cname) {
698 // the log record could be created for a platform logger
699 return (cname.equals("java.util.logging.Logger") ||
700 cname.startsWith("sun.util.logging.PlatformLogger"));
701 }
702 }
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.util.logging;
27 import java.time.Instant;
28 import java.util.*;
29 import java.util.concurrent.atomic.AtomicInteger;
30 import java.util.concurrent.atomic.AtomicLong;
31 import java.io.*;
32 import java.time.Clock;
33 import java.util.function.Predicate;
34
35 import static jdk.internal.logger.SimpleConsoleLogger.skipLoggingFrame;
36
37 /**
38 * LogRecord objects are used to pass logging requests between
39 * the logging framework and individual log Handlers.
40 * <p>
41 * When a LogRecord is passed into the logging framework it
42 * logically belongs to the framework and should no longer be
43 * used or updated by the client application.
44 * <p>
45 * Note that if the client application has not specified an
46 * explicit source method name and source class name, then the
47 * LogRecord class will infer them automatically when they are
48 * first accessed (due to a call on getSourceMethodName or
49 * getSourceClassName) by analyzing the call stack. Therefore,
50 * if a logging Handler wants to pass off a LogRecord to another
51 * thread, or to transmit it over RMI, and if it wishes to subsequently
52 * obtain method name or class name information it should call
53 * one of getSourceClassName or getSourceMethodName to force
54 * the values to be filled in.
643 // by which LogRecord will infer the source class name and source method name
644 // when analyzing the call stack.
645 // <p>
646 // The system property {@code jdk.logger.packages} can define a comma separated
647 // list of strings corresponding to additional package name prefixes that
648 // should be ignored when trying to infer the source caller class name.
649 // Those stack frames whose {@linkplain StackTraceElement#getClassName()
650 // declaring class name} start with one such prefix will be ignored.
651 // <p>
652 // This is primarily useful when providing utility logging classes wrapping
653 // a logger instance, as it makes it possible to instruct LogRecord to skip
654 // those utility frames when inferring the caller source class name.
655 // <p>
656 // The {@code jdk.logger.packages} system property is consulted only once.
657 // <p>
658 // This property is not standard, implementation specific, and yet
659 // undocumented (and thus subject to changes without notice).
660 //
661 private void inferCaller() {
662 needToInferCaller = false;
663 // Skip all frames until we have found the first logger frame.
664 Optional<StackWalker.StackFrame> frame = new CallerFinder().get();
665 frame.ifPresent(f -> {
666 setSourceClassName(f.getClassName());
667 setSourceMethodName(f.getMethodName());
668 });
669
670 // We haven't found a suitable frame, so just punt. This is
671 // OK as we are only committed to making a "best effort" here.
672 }
673
674 /*
675 * CallerFinder is a stateful predicate.
676 */
677 static final class CallerFinder implements Predicate<StackWalker.StackFrame> {
678 static final StackWalker WALKER = StackWalker.getInstance();
679
680 /**
681 * Returns StackFrame of the caller's frame.
682 * @return StackFrame of the caller's frame.
683 */
684 Optional<StackWalker.StackFrame> get() {
685 return WALKER.walk((s) -> s.filter(this).findFirst());
686 }
687
688 private boolean lookingForLogger = true;
689 /**
690 * Returns true if we have found the caller's frame, false if the frame
691 * must be skipped.
692 *
693 * @param t The frame info.
694 * @return true if we have found the caller's frame, false if the frame
695 * must be skipped.
696 */
697 @Override
698 public boolean test(StackWalker.StackFrame t) {
699 final String cname = t.getClassName();
700 // We should skip all frames until we have found the logger,
701 // because these frames could be frames introduced by e.g. custom
702 // sub classes of Handler.
703 if (lookingForLogger) {
704 // the log record could be created for a platform logger
705 lookingForLogger = !isLoggerImplFrame(cname);
706 return false;
707 }
708 // skip logging/logger infrastructure and reflection calls
709 return !skipLoggingFrame(cname);
710 }
711
712 private boolean isLoggerImplFrame(String cname) {
713 return (cname.equals("java.util.logging.Logger") ||
714 cname.startsWith("sun.util.logging.PlatformLogger"));
715 }
716 }
717 }
|