1 /*
2 * Copyright (c) 2000, 2012, 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
27 package java.util.logging;
28
29 import java.util.*;
30 import java.util.concurrent.CopyOnWriteArrayList;
31 import java.security.*;
32 import java.lang.ref.WeakReference;
33 import java.util.function.Supplier;
34
35 /**
36 * A Logger object is used to log messages for a specific
37 * system or application component. Loggers are normally named,
38 * using a hierarchical dot-separated namespace. Logger names
39 * can be arbitrary strings, but they should normally be based on
40 * the package name or class name of the logged component, such
41 * as java.net or javax.swing. In addition it is possible to create
42 * "anonymous" Loggers that are not stored in the Logger namespace.
43 * <p>
44 * Logger objects may be obtained by calls on one of the getLogger
45 * factory methods. These will either create a new Logger or
46 * return a suitable existing Logger. It is important to note that
47 * the Logger returned by one of the {@code getLogger} factory methods
48 * may be garbage collected at any time if a strong reference to the
49 * Logger is not kept.
50 * <p>
51 * Logging messages will be forwarded to registered Handler
52 * objects, which can forward the messages to a variety of
87 * it will inherit the ResourceBundle name from its parent,
88 * recursively up the tree.
89 * <p>
90 * Most of the logger output methods take a "msg" argument. This
91 * msg argument may be either a raw value or a localization key.
92 * During formatting, if the logger has (or inherits) a localization
93 * ResourceBundle and if the ResourceBundle has a mapping for the msg
94 * string, then the msg string is replaced by the localized value.
95 * Otherwise the original msg string is used. Typically, formatters use
96 * java.text.MessageFormat style formatting to format parameters, so
97 * for example a format string "{0} {1}" would format two parameters
98 * as strings.
99 * <p>
100 * A set of methods alternatively take a "msgSupplier" instead of a "msg"
101 * argument. These methods take a {@link Supplier}{@code <String>} function
102 * which is invoked to construct the desired log message only when the message
103 * actually is to be logged based on the effective log level thus eliminating
104 * unnecessary message construction. For example, if the developer wants to
105 * log system health status for diagnosis, with the String-accepting version,
106 * the code would look like:
107 <code><pre>
108
109 class DiagnosisMessages {
110 static String systemHealthStatus() {
111 // collect system health information
112 ...
113 }
114 }
115 ...
116 logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus());
117 </pre></code>
118 * With the above code, the health status is collected unnecessarily even when
119 * the log level FINER is disabled. With the Supplier-accepting version as
120 * below, the status will only be collected when the log level FINER is
121 * enabled.
122 <code><pre>
123
124 logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus);
125 </pre></code>
126 * <p>
127 * When mapping ResourceBundle names to ResourceBundles, the Logger
128 * will first try to use the Thread's ContextClassLoader. If that
129 * is null it will try the SystemClassLoader instead. As a temporary
130 * transition feature in the initial implementation, if the Logger is
131 * unable to locate a ResourceBundle from the ContextClassLoader or
132 * SystemClassLoader the Logger will also search up the class stack
133 * and use successive calling ClassLoaders to try to locate a ResourceBundle.
134 * (This call stack search is to allow containers to transition to
135 * using ContextClassLoaders and is likely to be removed in future
136 * versions.)
137 * <p>
138 * Formatting (including localization) is the responsibility of
139 * the output Handler, which will typically call a Formatter.
140 * <p>
141 * Note that formatting need not occur synchronously. It may be delayed
142 * until a LogRecord is actually written to an external sink.
143 * <p>
144 * The logging methods are grouped in five main categories:
145 * <ul>
146 * <li><p>
147 * There are a set of "log" methods that take a log level, a message
148 * string, and optionally some parameters to the message string.
149 * <li><p>
150 * There are a set of "logp" methods (for "log precise") that are
151 * like the "log" methods, but also take an explicit source class name
152 * and method name.
153 * <li><p>
154 * There are a set of "logrb" method (for "log with resource bundle")
155 * that are like the "logp" method, but also take an explicit resource
156 * bundle name for use in localizing the log message.
1524 * @param useParentHandlers true if output is to be sent to the
1525 * logger's parent.
1526 * @exception SecurityException if a security manager exists and if
1527 * the caller does not have LoggingPermission("control").
1528 */
1529 public void setUseParentHandlers(boolean useParentHandlers) {
1530 checkPermission();
1531 this.useParentHandlers = useParentHandlers;
1532 }
1533
1534 /**
1535 * Discover whether or not this logger is sending its output
1536 * to its parent logger.
1537 *
1538 * @return true if output is to be sent to the logger's parent
1539 */
1540 public boolean getUseParentHandlers() {
1541 return useParentHandlers;
1542 }
1543
1544 // Private utility method to map a resource bundle name to an
1545 // actual resource bundle, using a simple one-entry cache.
1546 // Returns null for a null name.
1547 // May also return null if we can't find the resource bundle and
1548 // there is no suitable previous cached value.
1549
1550 private synchronized ResourceBundle findResourceBundle(String name) {
1551 // Return a null bundle for a null name.
1552 if (name == null) {
1553 return null;
1554 }
1555
1556 Locale currentLocale = Locale.getDefault();
1557
1558 // Normally we should hit on our simple one entry cache.
1559 if (catalog != null && currentLocale == catalogLocale
1560 && name == catalogName) {
1561 return catalog;
1562 }
1563
1564 // Use the thread's context ClassLoader. If there isn't one,
1565 // use the SystemClassloader.
1566 ClassLoader cl = Thread.currentThread().getContextClassLoader();
1567 if (cl == null) {
1568 cl = ClassLoader.getSystemClassLoader();
1569 }
1570 try {
1571 catalog = ResourceBundle.getBundle(name, currentLocale, cl);
1572 catalogName = name;
1573 catalogLocale = currentLocale;
1574 return catalog;
1575 } catch (MissingResourceException ex) {
1576 // Woops. We can't find the ResourceBundle in the default
1577 // ClassLoader. Drop through.
1578 }
1579
1580
1581 // Fall back to searching up the call stack and trying each
1582 // calling ClassLoader.
1583 for (int ix = 0; ; ix++) {
1584 Class clz = sun.reflect.Reflection.getCallerClass(ix);
1585 if (clz == null) {
1586 break;
1587 }
1588 ClassLoader cl2 = clz.getClassLoader();
1589 if (cl2 == null) {
1590 cl2 = ClassLoader.getSystemClassLoader();
1591 }
1592 if (cl == cl2) {
1593 // We've already checked this classloader.
1594 continue;
1595 }
1596 cl = cl2;
1597 try {
1598 catalog = ResourceBundle.getBundle(name, currentLocale, cl);
1599 catalogName = name;
1600 catalogLocale = currentLocale;
1601 return catalog;
1602 } catch (MissingResourceException ex) {
1603 // Ok, this one didn't work either.
1604 // Drop through, and try the next one.
1605 }
1606 }
1607
1608 if (name.equals(catalogName)) {
1609 // Return the previous cached value for that name.
1610 // This may be null.
1611 return catalog;
1612 }
1613 // Sorry, we're out of luck.
1614 return null;
1615 }
1616
1617 // Private utility method to initialize our one entry
1618 // resource bundle name cache.
1619 // Note: for consistency reasons, we are careful to check
1620 // that a suitable ResourceBundle exists before setting the
1621 // resourceBundleName field.
1622 // Synchronized to prevent races in setting the field.
1623 private synchronized void setupResourceInfo(String name) {
1624 if (name == null) {
1625 return;
1626 }
1627
1628 if (resourceBundleName != null) {
1629 // this Logger already has a ResourceBundle
1630
1631 if (resourceBundleName.equals(name)) {
1632 // the names match so there is nothing more to do
1633 return;
1634 }
1635
1636 // cannot change ResourceBundles once they are set
1637 throw new IllegalArgumentException(
1638 resourceBundleName + " != " + name);
1639 }
1640
1641 ResourceBundle rb = findResourceBundle(name);
1642 if (rb == null) {
1643 // We've failed to find an expected ResourceBundle.
1644 throw new MissingResourceException("Can't find " + name + " bundle", name, "");
1645 }
1646 resourceBundleName = name;
1647 }
1648
1649 /**
1650 * Return the parent for this Logger.
1651 * <p>
1652 * This method returns the nearest extant parent in the namespace.
1653 * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
1654 * has been created but no logger "a.b.c" exists, then a call of
1655 * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
1656 * <p>
1657 * The result will be null if it is called on the root Logger
1658 * in the namespace.
1659 *
1660 * @return nearest existing parent Logger
1661 */
1662 public Logger getParent() {
|
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
27 package java.util.logging;
28
29 import java.lang.ref.WeakReference;
30 import java.util.ArrayList;
31 import java.util.Iterator;
32 import java.util.Locale;
33 import java.util.MissingResourceException;
34 import java.util.ResourceBundle;
35 import java.util.concurrent.CopyOnWriteArrayList;
36 import java.util.function.Supplier;
37
38 /**
39 * A Logger object is used to log messages for a specific
40 * system or application component. Loggers are normally named,
41 * using a hierarchical dot-separated namespace. Logger names
42 * can be arbitrary strings, but they should normally be based on
43 * the package name or class name of the logged component, such
44 * as java.net or javax.swing. In addition it is possible to create
45 * "anonymous" Loggers that are not stored in the Logger namespace.
46 * <p>
47 * Logger objects may be obtained by calls on one of the getLogger
48 * factory methods. These will either create a new Logger or
49 * return a suitable existing Logger. It is important to note that
50 * the Logger returned by one of the {@code getLogger} factory methods
51 * may be garbage collected at any time if a strong reference to the
52 * Logger is not kept.
53 * <p>
54 * Logging messages will be forwarded to registered Handler
55 * objects, which can forward the messages to a variety of
90 * it will inherit the ResourceBundle name from its parent,
91 * recursively up the tree.
92 * <p>
93 * Most of the logger output methods take a "msg" argument. This
94 * msg argument may be either a raw value or a localization key.
95 * During formatting, if the logger has (or inherits) a localization
96 * ResourceBundle and if the ResourceBundle has a mapping for the msg
97 * string, then the msg string is replaced by the localized value.
98 * Otherwise the original msg string is used. Typically, formatters use
99 * java.text.MessageFormat style formatting to format parameters, so
100 * for example a format string "{0} {1}" would format two parameters
101 * as strings.
102 * <p>
103 * A set of methods alternatively take a "msgSupplier" instead of a "msg"
104 * argument. These methods take a {@link Supplier}{@code <String>} function
105 * which is invoked to construct the desired log message only when the message
106 * actually is to be logged based on the effective log level thus eliminating
107 * unnecessary message construction. For example, if the developer wants to
108 * log system health status for diagnosis, with the String-accepting version,
109 * the code would look like:
110 <pre><code>
111
112 class DiagnosisMessages {
113 static String systemHealthStatus() {
114 // collect system health information
115 ...
116 }
117 }
118 ...
119 logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus());
120 </code></pre>
121 * With the above code, the health status is collected unnecessarily even when
122 * the log level FINER is disabled. With the Supplier-accepting version as
123 * below, the status will only be collected when the log level FINER is
124 * enabled.
125 <pre><code>
126
127 logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus);
128 </code></pre>
129 * <p>
130 * When mapping ResourceBundle names to ResourceBundles, the Logger
131 * will first try to use the Thread's ContextClassLoader. If that
132 * is null it will try the
133 * {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader} instead.
134 * <p>
135 * Formatting (including localization) is the responsibility of
136 * the output Handler, which will typically call a Formatter.
137 * <p>
138 * Note that formatting need not occur synchronously. It may be delayed
139 * until a LogRecord is actually written to an external sink.
140 * <p>
141 * The logging methods are grouped in five main categories:
142 * <ul>
143 * <li><p>
144 * There are a set of "log" methods that take a log level, a message
145 * string, and optionally some parameters to the message string.
146 * <li><p>
147 * There are a set of "logp" methods (for "log precise") that are
148 * like the "log" methods, but also take an explicit source class name
149 * and method name.
150 * <li><p>
151 * There are a set of "logrb" method (for "log with resource bundle")
152 * that are like the "logp" method, but also take an explicit resource
153 * bundle name for use in localizing the log message.
1521 * @param useParentHandlers true if output is to be sent to the
1522 * logger's parent.
1523 * @exception SecurityException if a security manager exists and if
1524 * the caller does not have LoggingPermission("control").
1525 */
1526 public void setUseParentHandlers(boolean useParentHandlers) {
1527 checkPermission();
1528 this.useParentHandlers = useParentHandlers;
1529 }
1530
1531 /**
1532 * Discover whether or not this logger is sending its output
1533 * to its parent logger.
1534 *
1535 * @return true if output is to be sent to the logger's parent
1536 */
1537 public boolean getUseParentHandlers() {
1538 return useParentHandlers;
1539 }
1540
1541 /**
1542 * Private utility method to map a resource bundle name to an
1543 * actual resource bundle, using a simple one-entry cache.
1544 * Returns null for a null name.
1545 * May also return null if we can't find the resource bundle and
1546 * there is no suitable previous cached value.
1547 *
1548 * @param name the ResourceBundle to locate
1549 * @return ResourceBundle specified by name or null if not found
1550 */
1551 private synchronized ResourceBundle findResourceBundle(String name) {
1552 // Return a null bundle for a null name.
1553 if (name == null) {
1554 return null;
1555 }
1556
1557 Locale currentLocale = Locale.getDefault();
1558
1559 // Normally we should hit on our simple one entry cache.
1560 if (catalog != null && currentLocale.equals(catalogLocale)
1561 && name.equals(catalogName)) {
1562 return catalog;
1563 }
1564
1565 // Use the thread's context ClassLoader. If there isn't one, use the
1566 // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}.
1567 ClassLoader cl = Thread.currentThread().getContextClassLoader();
1568 if (cl == null) {
1569 cl = ClassLoader.getSystemClassLoader();
1570 }
1571 try {
1572 catalog = ResourceBundle.getBundle(name, currentLocale, cl);
1573 catalogName = name;
1574 catalogLocale = currentLocale;
1575 return catalog;
1576 } catch (MissingResourceException ex) {
1577 return null;
1578 }
1579 }
1580
1581 // Private utility method to initialize our one entry
1582 // resource bundle name cache.
1583 // Note: for consistency reasons, we are careful to check
1584 // that a suitable ResourceBundle exists before setting the
1585 // resourceBundleName field.
1586 // Synchronized to prevent races in setting the field.
1587 private synchronized void setupResourceInfo(String name) {
1588 if (name == null) {
1589 return;
1590 }
1591
1592 if (resourceBundleName != null) {
1593 // this Logger already has a ResourceBundle
1594
1595 if (resourceBundleName.equals(name)) {
1596 // the names match so there is nothing more to do
1597 return;
1598 }
1599
1600 // cannot change ResourceBundles once they are set
1601 throw new IllegalArgumentException(
1602 resourceBundleName + " != " + name);
1603 }
1604
1605 if (findResourceBundle(name) == null) {
1606 // We've failed to find an expected ResourceBundle.
1607 throw new MissingResourceException("Can't find " + name + " bundle", name, "");
1608 }
1609 resourceBundleName = name;
1610 }
1611
1612 /**
1613 * Return the parent for this Logger.
1614 * <p>
1615 * This method returns the nearest extant parent in the namespace.
1616 * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
1617 * has been created but no logger "a.b.c" exists, then a call of
1618 * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
1619 * <p>
1620 * The result will be null if it is called on the root Logger
1621 * in the namespace.
1622 *
1623 * @return nearest existing parent Logger
1624 */
1625 public Logger getParent() {
|