1 /*
2 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
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
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.
55 * <p>
620 if (resourceBundleName != null) {
621 try {
622 // use system class loader to ensure the ResourceBundle
623 // instance is a different instance than null loader uses
624 final ResourceBundle bundle =
625 ResourceBundle.getBundle(resourceBundleName,
626 Locale.getDefault(),
627 ClassLoader.getSystemClassLoader());
628 resourceBundle = bundle;
629 } catch (MissingResourceException ex) {
630 // This is not a good place to throw an exception,
631 // so we simply leave the resourceBundle null.
632 resourceBundle = null;
633 }
634 }
635
636 needToInferCaller = false;
637 }
638
639 // Private method to infer the caller's class and method names
640 private void inferCaller() {
641 needToInferCaller = false;
642 JavaLangAccess access = SharedSecrets.getJavaLangAccess();
643 Throwable throwable = new Throwable();
644 int depth = access.getStackTraceDepth(throwable);
645
646 boolean lookingForLogger = true;
647 for (int ix = 0; ix < depth; ix++) {
648 // Calling getStackTraceElement directly prevents the VM
649 // from paying the cost of building the entire stack frame.
650 StackTraceElement frame =
651 access.getStackTraceElement(throwable, ix);
652 String cname = frame.getClassName();
653 boolean isLoggerImpl = isLoggerImplFrame(cname);
654 if (lookingForLogger) {
655 // Skip all frames until we have found the first logger frame.
656 if (isLoggerImpl) {
657 lookingForLogger = false;
658 }
659 } else {
660 if (!isLoggerImpl) {
661 // skip reflection call
662 if (!cname.startsWith("java.lang.reflect.") && !cname.startsWith("sun.reflect.")) {
663 // We've found the relevant frame.
664 setSourceClassName(cname);
665 setSourceMethodName(frame.getMethodName());
666 return;
667 }
668 }
669 }
670 }
671 // We haven't found a suitable frame, so just punt. This is
672 // OK as we are only committed to making a "best effort" here.
673 }
674
675 private boolean isLoggerImplFrame(String cname) {
676 // the log record could be created for a platform logger
677 return (cname.equals("java.util.logging.Logger") ||
678 cname.startsWith("java.util.logging.LoggingProxyImpl") ||
679 cname.startsWith("sun.util.logging."));
680 }
681 }
|
1 /*
2 * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
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.
56 * <p>
621 if (resourceBundleName != null) {
622 try {
623 // use system class loader to ensure the ResourceBundle
624 // instance is a different instance than null loader uses
625 final ResourceBundle bundle =
626 ResourceBundle.getBundle(resourceBundleName,
627 Locale.getDefault(),
628 ClassLoader.getSystemClassLoader());
629 resourceBundle = bundle;
630 } catch (MissingResourceException ex) {
631 // This is not a good place to throw an exception,
632 // so we simply leave the resourceBundle null.
633 resourceBundle = null;
634 }
635 }
636
637 needToInferCaller = false;
638 }
639
640 // Private method to infer the caller's class and method names
641 //
642 // Note:
643 // For testing purposes - it is possible to customize the process
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 }
|