| /* Logger.java -- a class for logging messages | |
| Copyright (C) 2002, 2004, 2006, 2007 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package java.util.logging; | |
| import gnu.java.lang.CPStringBuilder; | |
| import java.util.List; | |
| import java.util.MissingResourceException; | |
| import java.util.ResourceBundle; | |
| import java.security.AccessController; | |
| import java.security.PrivilegedAction; | |
| /** | |
| * A Logger is used for logging information about events. Usually, there is a | |
| * seprate logger for each subsystem or component, although there is a shared | |
| * instance for components that make only occasional use of the logging | |
| * framework. | |
| * <p> | |
| * It is common to name a logger after the name of a corresponding Java package. | |
| * Loggers are organized into a hierarchical namespace; for example, the logger | |
| * <code>"org.gnu.foo"</code> is the <em>parent</em> of logger | |
| * <code>"org.gnu.foo.bar"</code>. | |
| * <p> | |
| * A logger for a named subsystem can be obtained through {@link | |
| * java.util.logging.Logger#getLogger(java.lang.String)}. However, only code | |
| * which has been granted the permission to control the logging infrastructure | |
| * will be allowed to customize that logger. Untrusted code can obtain a | |
| * private, anonymous logger through {@link #getAnonymousLogger()} if it wants | |
| * to perform any modifications to the logger. | |
| * <p> | |
| * FIXME: Write more documentation. | |
| * | |
| * @author Sascha Brawer (brawer@acm.org) | |
| */ | |
| public class Logger | |
| { | |
| static final Logger root = new Logger("", null); | |
| /** | |
| * A logger provided to applications that make only occasional use of the | |
| * logging framework, typically early prototypes. Serious products are | |
| * supposed to create and use their own Loggers, so they can be controlled | |
| * individually. | |
| */ | |
| public static final Logger global; | |
| /** | |
| * Use to lock methods on this class instead of calling synchronize on methods | |
| * to avoid deadlocks. Yeah, no kidding, we got them :) | |
| */ | |
| private static final Object[] lock = new Object[0]; | |
| static | |
| { | |
| // Our class might be initialized from an unprivileged context | |
| global = (Logger) AccessController.doPrivileged(new PrivilegedAction() | |
| { | |
| public Object run() | |
| { | |
| return getLogger("global"); | |
| } | |
| }); | |
| } | |
| /** | |
| * The name of the Logger, or <code>null</code> if the logger is anonymous. | |
| * <p> | |
| * A previous version of the GNU Classpath implementation granted untrusted | |
| * code the permission to control any logger whose name was null. However, | |
| * test code revealed that the Sun J2SE 1.4 reference implementation enforces | |
| * the security control for any logger that was not created through | |
| * getAnonymousLogger, even if it has a null name. Therefore, a separate flag | |
| * {@link Logger#anonymous} was introduced. | |
| */ | |
| private final String name; | |
| /** | |
| * The name of the resource bundle used for localization. | |
| * <p> | |
| * This variable cannot be declared as <code>final</code> because its value | |
| * can change as a result of calling getLogger(String,String). | |
| */ | |
| private String resourceBundleName; | |
| /** | |
| * The resource bundle used for localization. | |
| * <p> | |
| * This variable cannot be declared as <code>final</code> because its value | |
| * can change as a result of calling getLogger(String,String). | |
| */ | |
| private ResourceBundle resourceBundle; | |
| private Filter filter; | |
| private final List handlerList = new java.util.ArrayList(4); | |
| private Handler[] handlers = new Handler[0]; | |
| /** | |
| * Indicates whether or not this logger is anonymous. While a | |
| * LoggingPermission is required for any modifications to a normal logger, | |
| * untrusted code can obtain an anonymous logger and modify it according to | |
| * its needs. | |
| * <p> | |
| * A previous version of the GNU Classpath implementation granted access to | |
| * every logger whose name was null. However, test code revealed that the Sun | |
| * J2SE 1.4 reference implementation enforces the security control for any | |
| * logger that was not created through getAnonymousLogger, even if it has a | |
| * null name. | |
| */ | |
| private boolean anonymous; | |
| private boolean useParentHandlers; | |
| private Level level; | |
| private Logger parent; | |
| /** | |
| * Constructs a Logger for a subsystem. Most applications do not need to | |
| * create new Loggers explicitly; instead, they should call the static factory | |
| * methods {@link #getLogger(java.lang.String,java.lang.String) getLogger} | |
| * (with ResourceBundle for localization) or | |
| * {@link #getLogger(java.lang.String) getLogger} (without ResourceBundle), | |
| * respectively. | |
| * | |
| * @param name the name for the logger, for example "java.awt" or | |
| * "com.foo.bar". The name should be based on the name of the | |
| * package issuing log records and consist of dot-separated Java | |
| * identifiers. | |
| * @param resourceBundleName the name of a resource bundle for localizing | |
| * messages, or <code>null</code> to indicate that messages do | |
| * not need to be localized. | |
| * @throws java.util.MissingResourceException if | |
| * <code>resourceBundleName</code> is not <code>null</code> | |
| * and no such bundle could be located. | |
| */ | |
| protected Logger(String name, String resourceBundleName) | |
| throws MissingResourceException | |
| { | |
| this.name = name; | |
| this.resourceBundleName = resourceBundleName; | |
| if (resourceBundleName == null) | |
| resourceBundle = null; | |
| else | |
| resourceBundle = ResourceBundle.getBundle(resourceBundleName); | |
| level = null; | |
| /* | |
| * This is null when the root logger is being constructed, and the root | |
| * logger afterwards. | |
| */ | |
| parent = root; | |
| useParentHandlers = (parent != null); | |
| } | |
| /** | |
| * Finds a registered logger for a subsystem, or creates one in case no logger | |
| * has been registered yet. | |
| * | |
| * @param name the name for the logger, for example "java.awt" or | |
| * "com.foo.bar". The name should be based on the name of the | |
| * package issuing log records and consist of dot-separated Java | |
| * identifiers. | |
| * @throws IllegalArgumentException if a logger for the subsystem identified | |
| * by <code>name</code> has already been created, but uses a a | |
| * resource bundle for localizing messages. | |
| * @throws NullPointerException if <code>name</code> is <code>null</code>. | |
| * @return a logger for the subsystem specified by <code>name</code> that | |
| * does not localize messages. | |
| */ | |
| public static Logger getLogger(String name) | |
| { | |
| return getLogger(name, null); | |
| } | |
| /** | |
| * Finds a registered logger for a subsystem, or creates one in case no logger | |
| * has been registered yet. | |
| * <p> | |
| * If a logger with the specified name has already been registered, the | |
| * behavior depends on the resource bundle that is currently associated with | |
| * the existing logger. | |
| * <ul> | |
| * <li>If the existing logger uses the same resource bundle as specified by | |
| * <code>resourceBundleName</code>, the existing logger is returned.</li> | |
| * <li>If the existing logger currently does not localize messages, the | |
| * existing logger is modified to use the bundle specified by | |
| * <code>resourceBundleName</code>. The existing logger is then returned. | |
| * Therefore, all subsystems currently using this logger will produce | |
| * localized messages from now on.</li> | |
| * <li>If the existing logger already has an associated resource bundle, but | |
| * a different one than specified by <code>resourceBundleName</code>, an | |
| * <code>IllegalArgumentException</code> is thrown.</li> | |
| * </ul> | |
| * | |
| * @param name the name for the logger, for example "java.awt" or | |
| * "org.gnu.foo". The name should be based on the name of the | |
| * package issuing log records and consist of dot-separated Java | |
| * identifiers. | |
| * @param resourceBundleName the name of a resource bundle for localizing | |
| * messages, or <code>null</code> to indicate that messages do | |
| * not need to be localized. | |
| * @return a logger for the subsystem specified by <code>name</code>. | |
| * @throws java.util.MissingResourceException if | |
| * <code>resourceBundleName</code> is not <code>null</code> | |
| * and no such bundle could be located. | |
| * @throws IllegalArgumentException if a logger for the subsystem identified | |
| * by <code>name</code> has already been created, but uses a | |
| * different resource bundle for localizing messages. | |
| * @throws NullPointerException if <code>name</code> is <code>null</code>. | |
| */ | |
| public static Logger getLogger(String name, String resourceBundleName) | |
| { | |
| LogManager lm = LogManager.getLogManager(); | |
| Logger result; | |
| if (name == null) | |
| throw new NullPointerException(); | |
| /* | |
| * Without synchronized(lm), it could happen that another thread would | |
| * create a logger between our calls to getLogger and addLogger. While | |
| * addLogger would indicate this by returning false, we could not be sure | |
| * that this other logger was still existing when we called getLogger a | |
| * second time in order to retrieve it -- note that LogManager is only | |
| * allowed to keep weak references to registered loggers, so Loggers can be | |
| * garbage collected at any time in general, and between our call to | |
| * addLogger and our second call go getLogger in particular. Of course, we | |
| * assume here that LogManager.addLogger etc. are synchronizing on the | |
| * global LogManager object. There is a comment in the implementation of | |
| * LogManager.addLogger referring to this comment here, so that any change | |
| * in the synchronization of LogManager will be reflected here. | |
| */ | |
| synchronized (lock) | |
| { | |
| synchronized (lm) | |
| { | |
| result = lm.getLogger(name); | |
| if (result == null) | |
| { | |
| boolean couldBeAdded; | |
| result = new Logger(name, resourceBundleName); | |
| couldBeAdded = lm.addLogger(result); | |
| if (! couldBeAdded) | |
| throw new IllegalStateException("cannot register new logger"); | |
| } | |
| else | |
| { | |
| /* | |
| * The logger already exists. Make sure it uses the same | |
| * resource bundle for localizing messages. | |
| */ | |
| String existingBundleName = result.getResourceBundleName(); | |
| /* | |
| * The Sun J2SE 1.4 reference implementation will return the | |
| * registered logger object, even if it does not have a resource | |
| * bundle associated with it. However, it seems to change the | |
| * resourceBundle of the registered logger to the bundle whose | |
| * name was passed to getLogger. | |
| */ | |
| if ((existingBundleName == null) && | |
| (resourceBundleName != null)) | |
| { | |
| /* | |
| * If ResourceBundle.getBundle throws an exception, the | |
| * existing logger will be unchanged. This would be | |
| * different if the assignment to resourceBundleName came | |
| * first. | |
| */ | |
| result.resourceBundle = | |
| ResourceBundle.getBundle(resourceBundleName); | |
| result.resourceBundleName = resourceBundleName; | |
| return result; | |
| } | |
| if ((existingBundleName != resourceBundleName) | |
| && ((existingBundleName == null) | |
| || !existingBundleName.equals(resourceBundleName))) | |
| { | |
| throw new IllegalArgumentException(); | |
| } | |
| } | |
| } | |
| } | |
| return result; | |
| } | |
| /** | |
| * Creates a new, unnamed logger. Unnamed loggers are not registered in the | |
| * namespace of the LogManager, and no special security permission is required | |
| * for changing their state. Therefore, untrusted applets are able to modify | |
| * their private logger instance obtained through this method. | |
| * <p> | |
| * The parent of the newly created logger will the the root logger, from which | |
| * the level threshold and the handlers are inherited. | |
| */ | |
| public static Logger getAnonymousLogger() | |
| { | |
| return getAnonymousLogger(null); | |
| } | |
| /** | |
| * Creates a new, unnamed logger. Unnamed loggers are not registered in the | |
| * namespace of the LogManager, and no special security permission is required | |
| * for changing their state. Therefore, untrusted applets are able to modify | |
| * their private logger instance obtained through this method. | |
| * <p> | |
| * The parent of the newly created logger will the the root logger, from which | |
| * the level threshold and the handlers are inherited. | |
| * | |
| * @param resourceBundleName the name of a resource bundle for localizing | |
| * messages, or <code>null</code> to indicate that messages do | |
| * not need to be localized. | |
| * @throws java.util.MissingResourceException if | |
| * <code>resourceBundleName</code> is not <code>null</code> | |
| * and no such bundle could be located. | |
| */ | |
| public static Logger getAnonymousLogger(String resourceBundleName) | |
| throws MissingResourceException | |
| { | |
| Logger result; | |
| result = new Logger(null, resourceBundleName); | |
| result.anonymous = true; | |
| return result; | |
| } | |
| /** | |
| * Returns the name of the resource bundle that is being used for localizing | |
| * messages. | |
| * | |
| * @return the name of the resource bundle used for localizing messages, or | |
| * <code>null</code> if the parent's resource bundle is used for | |
| * this purpose. | |
| */ | |
| public String getResourceBundleName() | |
| { | |
| synchronized (lock) | |
| { | |
| return resourceBundleName; | |
| } | |
| } | |
| /** | |
| * Returns the resource bundle that is being used for localizing messages. | |
| * | |
| * @return the resource bundle used for localizing messages, or | |
| * <code>null</code> if the parent's resource bundle is used for | |
| * this purpose. | |
| */ | |
| public ResourceBundle getResourceBundle() | |
| { | |
| synchronized (lock) | |
| { | |
| return resourceBundle; | |
| } | |
| } | |
| /** | |
| * Returns the severity level threshold for this <code>Handler</code>. All | |
| * log records with a lower severity level will be discarded; a log record of | |
| * the same or a higher level will be published unless an installed | |
| * <code>Filter</code> decides to discard it. | |
| * | |
| * @return the severity level below which all log messages will be discarded, | |
| * or <code>null</code> if the logger inherits the threshold from | |
| * its parent. | |
| */ | |
| public Level getLevel() | |
| { | |
| synchronized (lock) | |
| { | |
| return level; | |
| } | |
| } | |
| /** | |
| * Returns whether or not a message of the specified level would be logged by | |
| * this logger. | |
| * | |
| * @throws NullPointerException if <code>level</code> is <code>null</code>. | |
| */ | |
| public boolean isLoggable(Level level) | |
| { | |
| synchronized (lock) | |
| { | |
| if (this.level != null) | |
| return this.level.intValue() <= level.intValue(); | |
| if (parent != null) | |
| return parent.isLoggable(level); | |
| else | |
| return false; | |
| } | |
| } | |
| /** | |
| * Sets the severity level threshold for this <code>Handler</code>. All log | |
| * records with a lower severity level will be discarded immediately. A log | |
| * record of the same or a higher level will be published unless an installed | |
| * <code>Filter</code> decides to discard it. | |
| * | |
| * @param level the severity level below which all log messages will be | |
| * discarded, or <code>null</code> to indicate that the logger | |
| * should inherit the threshold from its parent. | |
| * @throws SecurityException if this logger is not anonymous, a security | |
| * manager exists, and the caller is not granted the permission to | |
| * control the logging infrastructure by having | |
| * LoggingPermission("control"). Untrusted code can obtain an | |
| * anonymous logger through the static factory method | |
| * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. | |
| */ | |
| public void setLevel(Level level) | |
| { | |
| synchronized (lock) | |
| { | |
| /* | |
| * An application is allowed to control an anonymous logger without | |
| * having the permission to control the logging infrastructure. | |
| */ | |
| if (! anonymous) | |
| LogManager.getLogManager().checkAccess(); | |
| this.level = level; | |
| } | |
| } | |
| public Filter getFilter() | |
| { | |
| synchronized (lock) | |
| { | |
| return filter; | |
| } | |
| } | |
| /** | |
| * @throws SecurityException if this logger is not anonymous, a security | |
| * manager exists, and the caller is not granted the permission to | |
| * control the logging infrastructure by having | |
| * LoggingPermission("control"). Untrusted code can obtain an | |
| * anonymous logger through the static factory method | |
| * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. | |
| */ | |
| public void setFilter(Filter filter) throws SecurityException | |
| { | |
| synchronized (lock) | |
| { | |
| /* | |
| * An application is allowed to control an anonymous logger without | |
| * having the permission to control the logging infrastructure. | |
| */ | |
| if (! anonymous) | |
| LogManager.getLogManager().checkAccess(); | |
| this.filter = filter; | |
| } | |
| } | |
| /** | |
| * Returns the name of this logger. | |
| * | |
| * @return the name of this logger, or <code>null</code> if the logger is | |
| * anonymous. | |
| */ | |
| public String getName() | |
| { | |
| /* | |
| * Note that the name of a logger cannot be changed during its lifetime, so | |
| * no synchronization is needed. | |
| */ | |
| return name; | |
| } | |
| /** | |
| * Passes a record to registered handlers, provided the record is considered | |
| * as loggable both by {@link #isLoggable(Level)} and a possibly installed | |
| * custom {@link #setFilter(Filter) filter}. | |
| * <p> | |
| * If the logger has been configured to use parent handlers, the record will | |
| * be forwarded to the parent of this logger in addition to being processed by | |
| * the handlers registered with this logger. | |
| * <p> | |
| * The other logging methods in this class are convenience methods that merely | |
| * create a new LogRecord and pass it to this method. Therefore, subclasses | |
| * usually just need to override this single method for customizing the | |
| * logging behavior. | |
| * | |
| * @param record the log record to be inspected and possibly forwarded. | |
| */ | |
| public void log(LogRecord record) | |
| { | |
| synchronized (lock) | |
| { | |
| if (!isLoggable(record.getLevel())) | |
| return; | |
| if ((filter != null) && ! filter.isLoggable(record)) | |
| return; | |
| /* | |
| * If no logger name has been set for the log record, use the name of | |
| * this logger. | |
| */ | |
| if (record.getLoggerName() == null) | |
| record.setLoggerName(name); | |
| /* | |
| * Avoid that some other thread is changing the logger hierarchy while | |
| * we are traversing it. | |
| */ | |
| synchronized (LogManager.getLogManager()) | |
| { | |
| Logger curLogger = this; | |
| do | |
| { | |
| /* | |
| * The Sun J2SE 1.4 reference implementation seems to call the | |
| * filter only for the logger whose log method is called, never | |
| * for any of its parents. Also, parent loggers publish log | |
| * record whatever their level might be. This is pretty weird, | |
| * but GNU Classpath tries to be as compatible as possible to | |
| * the reference implementation. | |
| */ | |
| for (int i = 0; i < curLogger.handlers.length; i++) | |
| curLogger.handlers[i].publish(record); | |
| if (curLogger.getUseParentHandlers() == false) | |
| break; | |
| curLogger = curLogger.getParent(); | |
| } | |
| while (parent != null); | |
| } | |
| } | |
| } | |
| public void log(Level level, String message) | |
| { | |
| if (isLoggable(level)) | |
| log(level, message, (Object[]) null); | |
| } | |
| public void log(Level level, String message, Object param) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(level)) | |
| { | |
| StackTraceElement caller = getCallerStackFrame(); | |
| logp(level, caller != null ? caller.getClassName() : "<unknown>", | |
| caller != null ? caller.getMethodName() : "<unknown>", | |
| message, param); | |
| } | |
| } | |
| } | |
| public void log(Level level, String message, Object[] params) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(level)) | |
| { | |
| StackTraceElement caller = getCallerStackFrame(); | |
| logp(level, caller != null ? caller.getClassName() : "<unknown>", | |
| caller != null ? caller.getMethodName() : "<unknown>", | |
| message, params); | |
| } | |
| } | |
| } | |
| public void log(Level level, String message, Throwable thrown) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(level)) | |
| { | |
| StackTraceElement caller = getCallerStackFrame(); | |
| logp(level, caller != null ? caller.getClassName() : "<unknown>", | |
| caller != null ? caller.getMethodName() : "<unknown>", | |
| message, thrown); | |
| } | |
| } | |
| } | |
| public void logp(Level level, String sourceClass, String sourceMethod, | |
| String message) | |
| { | |
| synchronized (lock) | |
| { | |
| logp(level, sourceClass, sourceMethod, message, (Object[]) null); | |
| } | |
| } | |
| public void logp(Level level, String sourceClass, String sourceMethod, | |
| String message, Object param) | |
| { | |
| synchronized (lock) | |
| { | |
| logp(level, sourceClass, sourceMethod, message, new Object[] { param }); | |
| } | |
| } | |
| private ResourceBundle findResourceBundle() | |
| { | |
| synchronized (lock) | |
| { | |
| if (resourceBundle != null) | |
| return resourceBundle; | |
| if (parent != null) | |
| return parent.findResourceBundle(); | |
| return null; | |
| } | |
| } | |
| private void logImpl(Level level, String sourceClass, String sourceMethod, | |
| String message, Object[] params) | |
| { | |
| synchronized (lock) | |
| { | |
| LogRecord rec = new LogRecord(level, message); | |
| rec.setResourceBundle(findResourceBundle()); | |
| rec.setSourceClassName(sourceClass); | |
| rec.setSourceMethodName(sourceMethod); | |
| rec.setParameters(params); | |
| log(rec); | |
| } | |
| } | |
| public void logp(Level level, String sourceClass, String sourceMethod, | |
| String message, Object[] params) | |
| { | |
| synchronized (lock) | |
| { | |
| logImpl(level, sourceClass, sourceMethod, message, params); | |
| } | |
| } | |
| public void logp(Level level, String sourceClass, String sourceMethod, | |
| String message, Throwable thrown) | |
| { | |
| synchronized (lock) | |
| { | |
| LogRecord rec = new LogRecord(level, message); | |
| rec.setResourceBundle(resourceBundle); | |
| rec.setSourceClassName(sourceClass); | |
| rec.setSourceMethodName(sourceMethod); | |
| rec.setThrown(thrown); | |
| log(rec); | |
| } | |
| } | |
| public void logrb(Level level, String sourceClass, String sourceMethod, | |
| String bundleName, String message) | |
| { | |
| synchronized (lock) | |
| { | |
| logrb(level, sourceClass, sourceMethod, bundleName, message, | |
| (Object[]) null); | |
| } | |
| } | |
| public void logrb(Level level, String sourceClass, String sourceMethod, | |
| String bundleName, String message, Object param) | |
| { | |
| synchronized (lock) | |
| { | |
| logrb(level, sourceClass, sourceMethod, bundleName, message, | |
| new Object[] { param }); | |
| } | |
| } | |
| public void logrb(Level level, String sourceClass, String sourceMethod, | |
| String bundleName, String message, Object[] params) | |
| { | |
| synchronized (lock) | |
| { | |
| LogRecord rec = new LogRecord(level, message); | |
| rec.setResourceBundleName(bundleName); | |
| rec.setSourceClassName(sourceClass); | |
| rec.setSourceMethodName(sourceMethod); | |
| rec.setParameters(params); | |
| log(rec); | |
| } | |
| } | |
| public void logrb(Level level, String sourceClass, String sourceMethod, | |
| String bundleName, String message, Throwable thrown) | |
| { | |
| synchronized (lock) | |
| { | |
| LogRecord rec = new LogRecord(level, message); | |
| rec.setResourceBundleName(bundleName); | |
| rec.setSourceClassName(sourceClass); | |
| rec.setSourceMethodName(sourceMethod); | |
| rec.setThrown(thrown); | |
| log(rec); | |
| } | |
| } | |
| public void entering(String sourceClass, String sourceMethod) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.FINER)) | |
| logp(Level.FINER, sourceClass, sourceMethod, "ENTRY"); | |
| } | |
| } | |
| public void entering(String sourceClass, String sourceMethod, Object param) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.FINER)) | |
| logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param); | |
| } | |
| } | |
| public void entering(String sourceClass, String sourceMethod, Object[] params) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.FINER)) | |
| { | |
| CPStringBuilder buf = new CPStringBuilder(80); | |
| buf.append("ENTRY"); | |
| for (int i = 0; i < params.length; i++) | |
| { | |
| buf.append(" {"); | |
| buf.append(i); | |
| buf.append('}'); | |
| } | |
| logp(Level.FINER, sourceClass, sourceMethod, buf.toString(), params); | |
| } | |
| } | |
| } | |
| public void exiting(String sourceClass, String sourceMethod) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.FINER)) | |
| logp(Level.FINER, sourceClass, sourceMethod, "RETURN"); | |
| } | |
| } | |
| public void exiting(String sourceClass, String sourceMethod, Object result) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.FINER)) | |
| logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result); | |
| } | |
| } | |
| public void throwing(String sourceClass, String sourceMethod, Throwable thrown) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.FINER)) | |
| logp(Level.FINER, sourceClass, sourceMethod, "THROW", thrown); | |
| } | |
| } | |
| /** | |
| * Logs a message with severity level SEVERE, indicating a serious failure | |
| * that prevents normal program execution. Messages at this level should be | |
| * understandable to an inexperienced, non-technical end user. Ideally, they | |
| * explain in simple words what actions the user can take in order to resolve | |
| * the problem. | |
| * | |
| * @see Level#SEVERE | |
| * @param message the message text, also used as look-up key if the logger is | |
| * localizing messages with a resource bundle. While it is possible | |
| * to pass <code>null</code>, this is not recommended, since a | |
| * logging message without text is unlikely to be helpful. | |
| */ | |
| public void severe(String message) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.SEVERE)) | |
| log(Level.SEVERE, message); | |
| } | |
| } | |
| /** | |
| * Logs a message with severity level WARNING, indicating a potential problem | |
| * that does not prevent normal program execution. Messages at this level | |
| * should be understandable to an inexperienced, non-technical end user. | |
| * Ideally, they explain in simple words what actions the user can take in | |
| * order to resolve the problem. | |
| * | |
| * @see Level#WARNING | |
| * @param message the message text, also used as look-up key if the logger is | |
| * localizing messages with a resource bundle. While it is possible | |
| * to pass <code>null</code>, this is not recommended, since a | |
| * logging message without text is unlikely to be helpful. | |
| */ | |
| public void warning(String message) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.WARNING)) | |
| log(Level.WARNING, message); | |
| } | |
| } | |
| /** | |
| * Logs a message with severity level INFO. {@link Level#INFO} is intended for | |
| * purely informational messages that do not indicate error or warning | |
| * situations. In the default logging configuration, INFO messages will be | |
| * written to the system console. For this reason, the INFO level should be | |
| * used only for messages that are important to end users and system | |
| * administrators. Messages at this level should be understandable to an | |
| * inexperienced, non-technical user. | |
| * | |
| * @param message the message text, also used as look-up key if the logger is | |
| * localizing messages with a resource bundle. While it is possible | |
| * to pass <code>null</code>, this is not recommended, since a | |
| * logging message without text is unlikely to be helpful. | |
| */ | |
| public void info(String message) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.INFO)) | |
| log(Level.INFO, message); | |
| } | |
| } | |
| /** | |
| * Logs a message with severity level CONFIG. {@link Level#CONFIG} is intended | |
| * for static configuration messages, for example about the windowing | |
| * environment, the operating system version, etc. | |
| * | |
| * @param message the message text, also used as look-up key if the logger is | |
| * localizing messages with a resource bundle. While it is possible | |
| * to pass <code>null</code>, this is not recommended, since a | |
| * logging message without text is unlikely to be helpful. | |
| */ | |
| public void config(String message) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.CONFIG)) | |
| log(Level.CONFIG, message); | |
| } | |
| } | |
| /** | |
| * Logs a message with severity level FINE. {@link Level#FINE} is intended for | |
| * messages that are relevant for developers using the component generating | |
| * log messages. Examples include minor, recoverable failures, or possible | |
| * inefficiencies. | |
| * | |
| * @param message the message text, also used as look-up key if the logger is | |
| * localizing messages with a resource bundle. While it is possible | |
| * to pass <code>null</code>, this is not recommended, since a | |
| * logging message without text is unlikely to be helpful. | |
| */ | |
| public void fine(String message) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.FINE)) | |
| log(Level.FINE, message); | |
| } | |
| } | |
| /** | |
| * Logs a message with severity level FINER. {@link Level#FINER} is intended | |
| * for rather detailed tracing, for example entering a method, returning from | |
| * a method, or throwing an exception. | |
| * | |
| * @param message the message text, also used as look-up key if the logger is | |
| * localizing messages with a resource bundle. While it is possible | |
| * to pass <code>null</code>, this is not recommended, since a | |
| * logging message without text is unlikely to be helpful. | |
| */ | |
| public void finer(String message) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.FINER)) | |
| log(Level.FINER, message); | |
| } | |
| } | |
| /** | |
| * Logs a message with severity level FINEST. {@link Level#FINEST} is intended | |
| * for highly detailed tracing, for example reaching a certain point inside | |
| * the body of a method. | |
| * | |
| * @param message the message text, also used as look-up key if the logger is | |
| * localizing messages with a resource bundle. While it is possible | |
| * to pass <code>null</code>, this is not recommended, since a | |
| * logging message without text is unlikely to be helpful. | |
| */ | |
| public void finest(String message) | |
| { | |
| synchronized (lock) | |
| { | |
| if (isLoggable(Level.FINEST)) | |
| log(Level.FINEST, message); | |
| } | |
| } | |
| /** | |
| * Adds a handler to the set of handlers that get notified when a log record | |
| * is to be published. | |
| * | |
| * @param handler the handler to be added. | |
| * @throws NullPointerException if <code>handler</code> is <code>null</code>. | |
| * @throws SecurityException if this logger is not anonymous, a security | |
| * manager exists, and the caller is not granted the permission to | |
| * control the logging infrastructure by having | |
| * LoggingPermission("control"). Untrusted code can obtain an | |
| * anonymous logger through the static factory method | |
| * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. | |
| */ | |
| public void addHandler(Handler handler) throws SecurityException | |
| { | |
| synchronized (lock) | |
| { | |
| if (handler == null) | |
| throw new NullPointerException(); | |
| /* | |
| * An application is allowed to control an anonymous logger without | |
| * having the permission to control the logging infrastructure. | |
| */ | |
| if (! anonymous) | |
| LogManager.getLogManager().checkAccess(); | |
| if (! handlerList.contains(handler)) | |
| { | |
| handlerList.add(handler); | |
| handlers = getHandlers(); | |
| } | |
| } | |
| } | |
| /** | |
| * Removes a handler from the set of handlers that get notified when a log | |
| * record is to be published. | |
| * | |
| * @param handler the handler to be removed. | |
| * @throws SecurityException if this logger is not anonymous, a security | |
| * manager exists, and the caller is not granted the permission to | |
| * control the logging infrastructure by having | |
| * LoggingPermission("control"). Untrusted code can obtain an | |
| * anonymous logger through the static factory method {@link | |
| * #getAnonymousLogger(java.lang.String) getAnonymousLogger}. | |
| * @throws NullPointerException if <code>handler</code> is <code>null</code>. | |
| */ | |
| public void removeHandler(Handler handler) throws SecurityException | |
| { | |
| synchronized (lock) | |
| { | |
| /* | |
| * An application is allowed to control an anonymous logger without | |
| * having the permission to control the logging infrastructure. | |
| */ | |
| if (! anonymous) | |
| LogManager.getLogManager().checkAccess(); | |
| if (handler == null) | |
| throw new NullPointerException(); | |
| handlerList.remove(handler); | |
| handlers = getHandlers(); | |
| } | |
| } | |
| /** | |
| * Returns the handlers currently registered for this Logger. When a log | |
| * record has been deemed as being loggable, it will be passed to all | |
| * registered handlers for publication. In addition, if the logger uses parent | |
| * handlers (see {@link #getUseParentHandlers() getUseParentHandlers} and | |
| * {@link #setUseParentHandlers(boolean) setUseParentHandlers}, the log | |
| * record will be passed to the parent's handlers. | |
| */ | |
| public Handler[] getHandlers() | |
| { | |
| synchronized (lock) | |
| { | |
| /* | |
| * We cannot return our internal handlers array because we do not have | |
| * any guarantee that the caller would not change the array entries. | |
| */ | |
| return (Handler[]) handlerList.toArray(new Handler[handlerList.size()]); | |
| } | |
| } | |
| /** | |
| * Returns whether or not this Logger forwards log records to handlers | |
| * registered for its parent loggers. | |
| * | |
| * @return <code>false</code> if this Logger sends log records merely to | |
| * Handlers registered with itself; <code>true</code> if this Logger | |
| * sends log records not only to Handlers registered with itself, but | |
| * also to those Handlers registered with parent loggers. | |
| */ | |
| public boolean getUseParentHandlers() | |
| { | |
| synchronized (lock) | |
| { | |
| return useParentHandlers; | |
| } | |
| } | |
| /** | |
| * Sets whether or not this Logger forwards log records to handlers registered | |
| * for its parent loggers. | |
| * | |
| * @param useParentHandlers <code>false</code> to let this Logger send log | |
| * records merely to Handlers registered with itself; | |
| * <code>true</code> to let this Logger send log records not only | |
| * to Handlers registered with itself, but also to those Handlers | |
| * registered with parent loggers. | |
| * @throws SecurityException if this logger is not anonymous, a security | |
| * manager exists, and the caller is not granted the permission to | |
| * control the logging infrastructure by having | |
| * LoggingPermission("control"). Untrusted code can obtain an | |
| * anonymous logger through the static factory method | |
| * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. | |
| */ | |
| public void setUseParentHandlers(boolean useParentHandlers) | |
| { | |
| synchronized (lock) | |
| { | |
| /* | |
| * An application is allowed to control an anonymous logger without | |
| * having the permission to control the logging infrastructure. | |
| */ | |
| if (! anonymous) | |
| LogManager.getLogManager().checkAccess(); | |
| this.useParentHandlers = useParentHandlers; | |
| } | |
| } | |
| /** | |
| * Returns the parent of this logger. By default, the parent is assigned by | |
| * the LogManager by inspecting the logger's name. | |
| * | |
| * @return the parent of this logger (as detemined by the LogManager by | |
| * inspecting logger names), the root logger if no other logger has a | |
| * name which is a prefix of this logger's name, or <code>null</code> | |
| * for the root logger. | |
| */ | |
| public Logger getParent() | |
| { | |
| synchronized (lock) | |
| { | |
| return parent; | |
| } | |
| } | |
| /** | |
| * Sets the parent of this logger. Usually, applications do not call this | |
| * method directly. Instead, the LogManager will ensure that the tree of | |
| * loggers reflects the hierarchical logger namespace. Basically, this method | |
| * should not be public at all, but the GNU implementation follows the API | |
| * specification. | |
| * | |
| * @throws NullPointerException if <code>parent</code> is <code>null</code>. | |
| * @throws SecurityException if this logger is not anonymous, a security | |
| * manager exists, and the caller is not granted the permission to | |
| * control the logging infrastructure by having | |
| * LoggingPermission("control"). Untrusted code can obtain an | |
| * anonymous logger through the static factory method | |
| * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. | |
| */ | |
| public void setParent(Logger parent) | |
| { | |
| synchronized (lock) | |
| { | |
| if (parent == null) | |
| throw new NullPointerException(); | |
| if (this == root) | |
| throw new IllegalArgumentException( | |
| "the root logger can only have a null parent"); | |
| /* | |
| * An application is allowed to control an anonymous logger without | |
| * having the permission to control the logging infrastructure. | |
| */ | |
| if (! anonymous) | |
| LogManager.getLogManager().checkAccess(); | |
| this.parent = parent; | |
| } | |
| } | |
| /** | |
| * Gets the StackTraceElement of the first class that is not this class. That | |
| * should be the initial caller of a logging method. | |
| * | |
| * @return caller of the initial logging method or null if unknown. | |
| */ | |
| private StackTraceElement getCallerStackFrame() | |
| { | |
| Throwable t = new Throwable(); | |
| StackTraceElement[] stackTrace = t.getStackTrace(); | |
| int index = 0; | |
| // skip to stackentries until this class | |
| while (index < stackTrace.length | |
| && ! stackTrace[index].getClassName().equals(getClass().getName())) | |
| index++; | |
| // skip the stackentries of this class | |
| while (index < stackTrace.length | |
| && stackTrace[index].getClassName().equals(getClass().getName())) | |
| index++; | |
| return index < stackTrace.length ? stackTrace[index] : null; | |
| } | |
| /** | |
| * Reset and close handlers attached to this logger. This function is package | |
| * private because it must only be available to the LogManager. | |
| */ | |
| void resetLogger() | |
| { | |
| for (int i = 0; i < handlers.length; i++) | |
| { | |
| handlers[i].close(); | |
| handlerList.remove(handlers[i]); | |
| } | |
| handlers = getHandlers(); | |
| } | |
| } |