/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.util.logging; import dalvik.system.DalvikLogHandler; import dalvik.system.DalvikLogging; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.concurrent.CopyOnWriteArrayList; /** * Loggers are used to log records to a variety of destinations such as log files or * the console. They use instances of {@link Handler} to actually do the destination-specific * operations. * * <p>Client applications can get named loggers by calling the {@code getLogger} * methods. They can also get anonymous loggers by calling the * {@code getAnonymousLogger} methods. Named loggers are organized in a * namespace hierarchy managed by a log manager. The naming convention is * usually the Java package naming convention. Anonymous loggers do not belong to any namespace. * * <p>Developers should use named loggers to enable logging to be controlled on a * per-{@code Logger} granularity. The recommended idiom is to create and assign the logger to * a {@code static final} field. This ensures that there's always a strong reference to the logger, * preventing it from being garbage collected. In particular, {@link LogManager#addLogger(Logger)} * will <i>not</i> keep your logger live. * * <p>Loggers "inherit" log level setting from their parent if their own level is * set to {@code null}. This is also true for the resource bundle. The logger's * resource bundle is used to localize the log messages if no resource bundle * name is given when a log method is called. If {@code getUseParentHandlers()} * returns {@code true}, loggers also inherit their parent's handlers. In this * context, "inherit" only means that "behavior" is inherited. The internal * field values will not change, for example, {@code getLevel()} still returns * {@code null}. * <p> * When loading a given resource bundle, the logger first tries to use the * context {@code ClassLoader}. If that fails, it tries the system {@code ClassLoader}. And if * that still fails, it searches up the class stack and uses each class's * {@code ClassLoader} to try to locate the resource bundle. * <p> * Some log methods accept log requests that do not specify the source class and * source method. In these cases, the logging framework will automatically infer * the calling class and method, but this is not guaranteed to be accurate. * <p> * Once a {@code LogRecord} object has been passed into the logging framework, * it is owned by the logging framework and the client applications should not * use it any longer. * <p> * All methods of this class are thread-safe. * * @see LogManager */ public class Logger { /** A handler for use when no handler optimization is possible. */ private static final DalvikLogHandler GENERAL_LOG_HANDLER = new DalvikLogHandler() { public void publish(Logger source, String tag, Level level, String message) { LogRecord record = new LogRecord(level, message); record.setLoggerName(source.name); source.setResourceBundle(record); source.log(record); } }; /** * The name of the global logger. Before using this, see the discussion of how to use * {@code Logger} in the class documentation. * @since 1.6 */ public static final String GLOBAL_LOGGER_NAME = "global"; /** * The global logger is provided as convenience for casual use. * @deprecated This is deadlock-prone. Use {@code Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)} * as a direct replacement, but read the discussion of how to use {@link Logger} in the class * documentation. */ @Deprecated public static final Logger global = new Logger(GLOBAL_LOGGER_NAME, null); /** * When converting the concurrent collection of handlers to an array, we * always pass a zero-length array to avoid size miscalculations. Passing * properly-sized arrays is non-atomic, and risks a null element in the * result. */ private static final Handler[] EMPTY_HANDLERS_ARRAY = new Handler[0]; /** The name of this logger. */ private volatile String name; /** The parent logger of this logger. */ Logger parent; /** The logging level of this logger, or null if none is set. */ volatile Level levelObjVal; /** * The effective logging level of this logger. In order of preference this * is the first applicable of: * <ol> * <li>the int value of this logger's {@link #levelObjVal} * <li>the logging level of the parent * <li>the default level ({@link Level#INFO}) * </ol> */ volatile int levelIntVal = Level.INFO.intValue(); /** The filter. */ private Filter filter; /** * The resource bundle used to localize logging messages. If null, no * localization will be performed. */ private volatile String resourceBundleName; /** The loaded resource bundle according to the specified name. */ private volatile ResourceBundle resourceBundle; /** * The handlers attached to this logger. Eagerly initialized and * concurrently modified. */ private final List<Handler> handlers = new CopyOnWriteArrayList<Handler>(); /** True to notify the parent's handlers of each log message. */ private boolean notifyParentHandlers = true; /** * Indicates whether this logger is named. Only {@link #getAnonymousLogger * anonymous loggers} are unnamed. */ private boolean isNamed = true; /** * Child loggers. Should be accessed only while synchronized on {@code * LogManager.getLogManager()}. */ final List<Logger> children = new ArrayList<Logger>(); /** the tag used for optimized logging. Derived from the logger name. */ private final String androidTag; /** Handler delegate for either optimized or standard logging. */ private volatile DalvikLogHandler dalvikLogHandler = GENERAL_LOG_HANDLER; /** * We've optimized for the common case: logging to a single handler that * implements {@link DalvikLogHandler}. This is how Android framework * applications are configured by default. * * <p>This optimization has been measured to show a 2.75x improvement in * throughput in the common case: 154ns vs. 56ns per message on a Cortex-A8. * Direct use of {@code android.util.Log} takes 29ns per message. * * <p>Each time the handler configuration changes, either directly or * indirectly, it's necessary to either turn on or off this optimization. * When the optimization is off, {@link #dalvikLogHandler} is assigned to * {@link #GENERAL_LOG_HANDLER} which can satisfy arbitrary configuration. * When the optimization is possible, {@link #dalvikLogHandler} is assigned * to the user's efficient implementation. In pratice this is usually the * {@code com.android.internal.logging.AndroidHandler}. */ void updateDalvikLogHandler() { DalvikLogHandler newLogHandler = GENERAL_LOG_HANDLER; Logger parent = this.parent; if (getClass() != Logger.class) { /* * Do nothing. Subclasses aren't eligible for the optimization * because they may override methods like getHandlers() or * log(LogRecord). */ } else if (parent == null) { // we use an iterator rather than size()+get() for safe concurrency Iterator<Handler> h = handlers.iterator(); if (h.hasNext()) { Handler firstHandler = h.next(); if (!h.hasNext() && firstHandler instanceof DalvikLogHandler) { /* * At this point, we're eligible for the optimization. We've * satisfied these constraints: * 1. This is not a subclass of logger * 2. This is a root logger (no parent) * 3. There is exactly one handler installed * 4. That handler is a DalvikLogHandler */ newLogHandler = (DalvikLogHandler) firstHandler; } } } else if (handlers.isEmpty() && notifyParentHandlers) { /* * At this point, we're eligible for the optimization if our parent * logger is eligible. We've satisfied these constraints: * 1. This is not a subclass of logger * 2. our parent exists * 3. we have no handlers of our own * 4. we notify our parent's handlers */ newLogHandler = parent.dalvikLogHandler; } if (newLogHandler == this.dalvikLogHandler) { return; } this.dalvikLogHandler = newLogHandler; for (Logger logger : children) { logger.updateDalvikLogHandler(); } } /** * Constructs a {@code Logger} object with the supplied name and resource * bundle name; {@code notifiyParentHandlers} is set to {@code true}. * <p> * Notice : Loggers use a naming hierarchy. Thus "z.x.y" is a child of "z.x". * * @param name * the name of this logger, may be {@code null} for anonymous * loggers. * @param resourceBundleName * the name of the resource bundle used to localize logging * messages, may be {@code null}. * @throws MissingResourceException * if the specified resource bundle can not be loaded. */ protected Logger(String name, String resourceBundleName) { this.name = name; initResourceBundle(resourceBundleName); this.androidTag = DalvikLogging.loggerNameToTag(name); updateDalvikLogHandler(); } /** * Load the specified resource bundle, use privileged code. * * @param resourceBundleName * the name of the resource bundle to load, cannot be {@code null}. * @return the loaded resource bundle. * @throws MissingResourceException * if the specified resource bundle can not be loaded. */ static ResourceBundle loadResourceBundle(String resourceBundleName) { // try context class loader to load the resource ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl != null) { try { return ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(), cl); } catch (MissingResourceException ignored) { // Failed to load using context class loader, ignore } } // try system class loader to load the resource cl = ClassLoader.getSystemClassLoader(); if (cl != null) { try { return ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(), cl); } catch (MissingResourceException ignored) { // Failed to load using system class loader, ignore } } throw new MissingResourceException("Failed to load the specified resource bundle \"" + resourceBundleName + "\"", resourceBundleName, null); } /** * Gets an anonymous logger to use internally in a thread. Anonymous loggers * are not registered in the log manager's namespace. No security checks * will be performed when updating an anonymous logger's control settings. * <p> * The anonymous loggers' parent is set to be the root logger. This way it * inherits the default logging level and handlers from the root logger. * * @return a new instance of anonymous logger. */ public static Logger getAnonymousLogger() { return getAnonymousLogger(null); } /** * Gets an anonymous logger to use internally in a thread. Anonymous loggers * are not registered in the log manager's namespace. No security checks * will be performed when updating an anonymous logger's control settings. * <p> * The anonymous loggers' parent is set to be the root logger. This way it * inherits default logging level and handlers from the root logger. * * @param resourceBundleName * the name of the resource bundle used to localize log messages. * @return a new instance of anonymous logger. * @throws MissingResourceException * if the specified resource bundle can not be loaded. */ public static Logger getAnonymousLogger(String resourceBundleName) { Logger result = new Logger(null, resourceBundleName); result.isNamed = false; LogManager logManager = LogManager.getLogManager(); logManager.setParent(result, logManager.getLogger("")); return result; } /** * Initializes this logger's resource bundle. * * @throws IllegalArgumentException if this logger's resource bundle already * exists and is different from the resource bundle specified. */ private synchronized void initResourceBundle(String resourceBundleName) { String current = this.resourceBundleName; if (current != null) { if (current.equals(resourceBundleName)) { return; } else { throw new IllegalArgumentException("Resource bundle name '" + resourceBundleName + "' is inconsistent with the existing '" + current + "'"); } } if (resourceBundleName != null) { this.resourceBundle = loadResourceBundle(resourceBundleName); this.resourceBundleName = resourceBundleName; } } /** * Gets a named logger. The returned logger may already exist or may be * newly created. In the latter case, its level will be set to the * configured level according to the {@code LogManager}'s properties. * * @param name * the name of the logger to get, cannot be {@code null}. * @return a named logger. * @throws MissingResourceException * If the specified resource bundle can not be loaded. */ public static Logger getLogger(String name) { return LogManager.getLogManager().getOrCreate(name, null); } /** * Gets a named logger associated with the supplied resource bundle. The * resource bundle will be used to localize logging messages. * * @param name * the name of the logger to get, cannot be {@code null}. * @param resourceBundleName * the name of the resource bundle, may be {@code null}. * @throws IllegalArgumentException * if the logger identified by {@code name} is associated with a * resource bundle and its name is not equal to * {@code resourceBundleName}. * @throws MissingResourceException * if the name of the resource bundle cannot be found. * @return a named logger. */ public static Logger getLogger(String name, String resourceBundleName) { Logger result = LogManager.getLogManager() .getOrCreate(name, resourceBundleName); result.initResourceBundle(resourceBundleName); return result; } /** * Returns the global {@code Logger}. * @since 1.7 */ public static Logger getGlobal() { return global; } /** * Adds a handler to this logger. The {@code name} will be fed with log * records received by this logger. * * @param handler * the handler object to add, cannot be {@code null}. */ public void addHandler(Handler handler) { if (handler == null) { throw new NullPointerException("handler == null"); } // Anonymous loggers can always add handlers if (this.isNamed) { LogManager.getLogManager().checkAccess(); } this.handlers.add(handler); updateDalvikLogHandler(); } /** * Set the logger's manager and initializes its configuration from the * manager's properties. */ void setManager(LogManager manager) { String levelProperty = manager.getProperty(name + ".level"); if (levelProperty != null) { try { manager.setLevelRecursively(Logger.this, Level.parse(levelProperty)); } catch (IllegalArgumentException invalidLevel) { invalidLevel.printStackTrace(); } } String handlersPropertyName = name.isEmpty() ? "handlers" : name + ".handlers"; String handlersProperty = manager.getProperty(handlersPropertyName); if (handlersProperty != null) { for (String handlerName : handlersProperty.split(",|\\s")) { if (handlerName.isEmpty()) { continue; } final Handler handler; try { handler = (Handler) LogManager.getInstanceByClass(handlerName); } catch (Exception invalidHandlerName) { invalidHandlerName.printStackTrace(); continue; } try { String level = manager.getProperty(handlerName + ".level"); if (level != null) { handler.setLevel(Level.parse(level)); } } catch (Exception invalidLevel) { invalidLevel.printStackTrace(); } handlers.add(handler); } } updateDalvikLogHandler(); } /** * Gets all the handlers associated with this logger. * * @return an array of all the handlers associated with this logger. */ public Handler[] getHandlers() { return handlers.toArray(EMPTY_HANDLERS_ARRAY); } /** * Removes a handler from this logger. If the specified handler does not * exist then this method has no effect. * * @param handler * the handler to be removed. */ public void removeHandler(Handler handler) { // Anonymous loggers can always remove handlers if (this.isNamed) { LogManager.getLogManager().checkAccess(); } if (handler == null) { return; } this.handlers.remove(handler); updateDalvikLogHandler(); } /** * Gets the filter used by this logger. * * @return the filter used by this logger, may be {@code null}. */ public Filter getFilter() { return this.filter; } /** * Sets the filter used by this logger. * * @param newFilter * the filter to set, may be {@code null}. */ public void setFilter(Filter newFilter) { // Anonymous loggers can always set the filter if (this.isNamed) { LogManager.getLogManager().checkAccess(); } filter = newFilter; } /** * Gets the logging level of this logger. A {@code null} level indicates * that this logger inherits its parent's level. * * @return the logging level of this logger. */ public Level getLevel() { return levelObjVal; } /** * Sets the logging level for this logger. A {@code null} level indicates * that this logger will inherit its parent's level. * * @param newLevel * the logging level to set. */ public void setLevel(Level newLevel) { // Anonymous loggers can always set the level LogManager logManager = LogManager.getLogManager(); if (this.isNamed) { logManager.checkAccess(); } logManager.setLevelRecursively(this, newLevel); } /** * Gets the flag which indicates whether to use the handlers of this * logger's parent to publish incoming log records, potentially recursively * up the namespace. * * @return {@code true} if set to use parent's handlers, {@code false} * otherwise. */ public boolean getUseParentHandlers() { return this.notifyParentHandlers; } /** * Sets the flag which indicates whether to use the handlers of this * logger's parent, potentially recursively up the namespace. * * @param notifyParentHandlers * the new flag indicating whether to use the parent's handlers. */ public void setUseParentHandlers(boolean notifyParentHandlers) { // Anonymous loggers can always set the useParentHandlers flag if (this.isNamed) { LogManager.getLogManager().checkAccess(); } this.notifyParentHandlers = notifyParentHandlers; updateDalvikLogHandler(); } /** * Gets the nearest parent of this logger in the namespace, a {@code null} * value will be returned if called on the root logger. * * @return the parent of this logger in the namespace. */ public Logger getParent() { return parent; } /** * Sets the parent of this logger in the namespace. This method should be * used by the {@code LogManager} object only. * * @param parent * the parent logger to set. */ public void setParent(Logger parent) { if (parent == null) { throw new NullPointerException("parent == null"); } // even anonymous loggers are checked LogManager logManager = LogManager.getLogManager(); logManager.checkAccess(); logManager.setParent(this, parent); } /** * Gets the name of this logger, {@code null} for anonymous loggers. * * @return the name of this logger. */ public String getName() { return this.name; } /** * Gets the loaded resource bundle used by this logger to localize logging * messages. If the value is {@code null}, the parent's resource bundle will be * inherited. * * @return the loaded resource bundle used by this logger. */ public ResourceBundle getResourceBundle() { return this.resourceBundle; } /** * Gets the name of the loaded resource bundle used by this logger to * localize logging messages. If the value is {@code null}, the parent's resource * bundle name will be inherited. * * @return the name of the loaded resource bundle used by this logger. */ public String getResourceBundleName() { return this.resourceBundleName; } /** * This method is for compatibility. Tests written to the reference * implementation API imply that the isLoggable() method is not called * directly. This behavior is important because subclass may override * isLoggable() method, so that affect the result of log methods. */ private boolean internalIsLoggable(Level l) { int effectiveLevel = levelIntVal; if (effectiveLevel == Level.OFF.intValue()) { // always return false if the effective level is off return false; } return l.intValue() >= effectiveLevel; } /** * Determines whether this logger will actually log messages of the * specified level. The effective level used to do the determination may be * inherited from its parent. The default level is {@code Level.INFO}. * * @param l * the level to check. * @return {@code true} if this logger will actually log this level, * otherwise {@code false}. */ public boolean isLoggable(Level l) { return internalIsLoggable(l); } /** * Sets the resource bundle and its name for a supplied LogRecord object. * This method first tries to use this logger's resource bundle if any, * otherwise try to inherit from this logger's parent, recursively up the * namespace. */ private void setResourceBundle(LogRecord record) { for (Logger p = this; p != null; p = p.parent) { String resourceBundleName = p.resourceBundleName; if (resourceBundleName != null) { record.setResourceBundle(p.resourceBundle); record.setResourceBundleName(resourceBundleName); return; } } } /** * Logs a message indicating that a method has been entered. A log record * with log level {@code Level.FINER}, log message "ENTRY", the specified * source class name and source method name is submitted for logging. * * @param sourceClass * the calling class name. * @param sourceMethod * the method name. */ public void entering(String sourceClass, String sourceMethod) { if (!internalIsLoggable(Level.FINER)) { return; } LogRecord record = new LogRecord(Level.FINER, "ENTRY"); record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); setResourceBundle(record); log(record); } /** * Logs a message indicating that a method has been entered. A log record * with log level {@code Level.FINER}, log message "ENTRY", the specified * source class name, source method name and one parameter is submitted for * logging. * * @param sourceClass * the source class name. * @param sourceMethod * the source method name. * @param param * the parameter for the method call. */ public void entering(String sourceClass, String sourceMethod, Object param) { if (!internalIsLoggable(Level.FINER)) { return; } LogRecord record = new LogRecord(Level.FINER, "ENTRY" + " {0}"); record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); record.setParameters(new Object[] { param }); setResourceBundle(record); log(record); } /** * Logs a message indicating that a method has been entered. A log record * with log level {@code Level.FINER}, log message "ENTRY", the specified * source class name, source method name and array of parameters is * submitted for logging. * * @param sourceClass * the source class name. * @param sourceMethod * the source method name. * @param params * an array of parameters for the method call. */ public void entering(String sourceClass, String sourceMethod, Object[] params) { if (!internalIsLoggable(Level.FINER)) { return; } String msg = "ENTRY"; if (params != null) { StringBuilder msgBuffer = new StringBuilder("ENTRY"); for (int i = 0; i < params.length; i++) { msgBuffer.append(" {").append(i).append("}"); } msg = msgBuffer.toString(); } LogRecord record = new LogRecord(Level.FINER, msg); record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); record.setParameters(params); setResourceBundle(record); log(record); } /** * Logs a message indicating that a method is exited. A log record with log * level {@code Level.FINER}, log message "RETURN", the specified source * class name and source method name is submitted for logging. * * @param sourceClass * the calling class name. * @param sourceMethod * the method name. */ public void exiting(String sourceClass, String sourceMethod) { if (!internalIsLoggable(Level.FINER)) { return; } LogRecord record = new LogRecord(Level.FINER, "RETURN"); record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); setResourceBundle(record); log(record); } /** * Logs a message indicating that a method is exited. A log record with log * level {@code Level.FINER}, log message "RETURN", the specified source * class name, source method name and return value is submitted for logging. * * @param sourceClass * the source class name. * @param sourceMethod * the source method name. * @param result * the return value of the method call. */ public void exiting(String sourceClass, String sourceMethod, Object result) { if (!internalIsLoggable(Level.FINER)) { return; } LogRecord record = new LogRecord(Level.FINER, "RETURN" + " {0}"); record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); record.setParameters(new Object[] { result }); setResourceBundle(record); log(record); } /** * Logs a message indicating that an exception is thrown. A log record with * log level {@code Level.FINER}, log message "THROW", the specified source * class name, source method name and the {@code Throwable} object is * submitted for logging. * * @param sourceClass * the source class name. * @param sourceMethod * the source method name. * @param thrown * the {@code Throwable} object. */ public void throwing(String sourceClass, String sourceMethod, Throwable thrown) { if (!internalIsLoggable(Level.FINER)) { return; } LogRecord record = new LogRecord(Level.FINER, "THROW"); record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); record.setThrown(thrown); setResourceBundle(record); log(record); } /** * Logs a message of level {@code Level.SEVERE}; the message is transmitted * to all subscribed handlers. * * @param msg * the message to log. */ public void severe(String msg) { log(Level.SEVERE, msg); } /** * Logs a message of level {@code Level.WARNING}; the message is * transmitted to all subscribed handlers. * * @param msg * the message to log. */ public void warning(String msg) { log(Level.WARNING, msg); } /** * Logs a message of level {@code Level.INFO}; the message is transmitted * to all subscribed handlers. * * @param msg * the message to log. */ public void info(String msg) { log(Level.INFO, msg); } /** * Logs a message of level {@code Level.CONFIG}; the message is transmitted * to all subscribed handlers. * * @param msg * the message to log. */ public void config(String msg) { log(Level.CONFIG, msg); } /** * Logs a message of level {@code Level.FINE}; the message is transmitted * to all subscribed handlers. * * @param msg * the message to log. */ public void fine(String msg) { log(Level.FINE, msg); } /** * Logs a message of level {@code Level.FINER}; the message is transmitted * to all subscribed handlers. * * @param msg * the message to log. */ public void finer(String msg) { log(Level.FINER, msg); } /** * Logs a message of level {@code Level.FINEST}; the message is transmitted * to all subscribed handlers. * * @param msg * the message to log. */ public void finest(String msg) { log(Level.FINEST, msg); } /** * Logs a message of the specified level. The message is transmitted to all * subscribed handlers. * * @param logLevel * the level of the specified message. * @param msg * the message to log. */ public void log(Level logLevel, String msg) { if (!internalIsLoggable(logLevel)) { return; } dalvikLogHandler.publish(this, androidTag, logLevel, msg); } /** * Logs a message of the specified level with the supplied parameter. The * message is then transmitted to all subscribed handlers. * * @param logLevel * the level of the given message. * @param msg * the message to log. * @param param * the parameter associated with the event that is logged. */ public void log(Level logLevel, String msg, Object param) { if (!internalIsLoggable(logLevel)) { return; } LogRecord record = new LogRecord(logLevel, msg); record.setLoggerName(this.name); record.setParameters(new Object[] { param }); setResourceBundle(record); log(record); } /** * Logs a message of the specified level with the supplied parameter array. * The message is then transmitted to all subscribed handlers. * * @param logLevel * the level of the given message * @param msg * the message to log. * @param params * the parameter array associated with the event that is logged. */ public void log(Level logLevel, String msg, Object[] params) { if (!internalIsLoggable(logLevel)) { return; } LogRecord record = new LogRecord(logLevel, msg); record.setLoggerName(this.name); record.setParameters(params); setResourceBundle(record); log(record); } /** * Logs a message of the specified level with the supplied {@code Throwable} * object. The message is then transmitted to all subscribed handlers. * * @param logLevel * the level of the given message. * @param msg * the message to log. * @param thrown * the {@code Throwable} object associated with the event that is * logged. */ public void log(Level logLevel, String msg, Throwable thrown) { if (!internalIsLoggable(logLevel)) { return; } LogRecord record = new LogRecord(logLevel, msg); record.setLoggerName(this.name); record.setThrown(thrown); setResourceBundle(record); log(record); } /** * Logs a given log record. Only records with a logging level that is equal * or greater than this logger's level will be submitted to this logger's * handlers for logging. If {@code getUseParentHandlers()} returns {@code * true}, the log record will also be submitted to the handlers of this * logger's parent, potentially recursively up the namespace. * <p> * Since all other log methods call this method to actually perform the * logging action, subclasses of this class can override this method to * catch all logging activities. * </p> * * @param record * the log record to be logged. */ public void log(LogRecord record) { if (!internalIsLoggable(record.getLevel())) { return; } // apply the filter if any Filter f = filter; if (f != null && !f.isLoggable(record)) { return; } /* * call the handlers of this logger, throw any exception that occurs */ Handler[] allHandlers = getHandlers(); for (Handler element : allHandlers) { element.publish(record); } // call the parent's handlers if set useParentHandlers Logger temp = this; Logger theParent = temp.parent; while (theParent != null && temp.getUseParentHandlers()) { Handler[] ha = theParent.getHandlers(); for (Handler element : ha) { element.publish(record); } temp = theParent; theParent = temp.parent; } } /** * Logs a message of the given level with the specified source class name * and source method name. * * @param logLevel * the level of the given message. * @param sourceClass * the source class name. * @param sourceMethod * the source method name. * @param msg * the message to be logged. */ public void logp(Level logLevel, String sourceClass, String sourceMethod, String msg) { if (!internalIsLoggable(logLevel)) { return; } LogRecord record = new LogRecord(logLevel, msg); record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); setResourceBundle(record); log(record); } /** * Logs a message of the given level with the specified source class name, * source method name and parameter. * * @param logLevel * the level of the given message * @param sourceClass * the source class name * @param sourceMethod * the source method name * @param msg * the message to be logged * @param param * the parameter associated with the event that is logged. */ public void logp(Level logLevel, String sourceClass, String sourceMethod, String msg, Object param) { if (!internalIsLoggable(logLevel)) { return; } LogRecord record = new LogRecord(logLevel, msg); record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); record.setParameters(new Object[] { param }); setResourceBundle(record); log(record); } /** * Logs a message of the given level with the specified source class name, * source method name and parameter array. * * @param logLevel * the level of the given message. * @param sourceClass * the source class name. * @param sourceMethod * the source method name. * @param msg * the message to be logged. * @param params * the parameter array associated with the event that is logged. */ public void logp(Level logLevel, String sourceClass, String sourceMethod, String msg, Object[] params) { if (!internalIsLoggable(logLevel)) { return; } LogRecord record = new LogRecord(logLevel, msg); record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); record.setParameters(params); setResourceBundle(record); log(record); } /** * Logs a message of the given level with the specified source class name, * source method name and {@code Throwable} object. * * @param logLevel * the level of the given message. * @param sourceClass * the source class name. * @param sourceMethod * the source method name. * @param msg * the message to be logged. * @param thrown * the {@code Throwable} object. */ public void logp(Level logLevel, String sourceClass, String sourceMethod, String msg, Throwable thrown) { if (!internalIsLoggable(logLevel)) { return; } LogRecord record = new LogRecord(logLevel, msg); record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); record.setThrown(thrown); setResourceBundle(record); log(record); } /** * Logs a message of the given level with the specified source class name * and source method name, using the given resource bundle to localize the * message. If {@code bundleName} is null, the empty string or not valid then * the message is not localized. * * @param logLevel * the level of the given message. * @param sourceClass * the source class name. * @param sourceMethod * the source method name. * @param bundleName * the name of the resource bundle used to localize the message. * @param msg * the message to be logged. */ public void logrb(Level logLevel, String sourceClass, String sourceMethod, String bundleName, String msg) { if (!internalIsLoggable(logLevel)) { return; } LogRecord record = new LogRecord(logLevel, msg); if (bundleName != null) { try { record.setResourceBundle(loadResourceBundle(bundleName)); } catch (MissingResourceException e) { // ignore } record.setResourceBundleName(bundleName); } record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); log(record); } /** * Logs a message of the given level with the specified source class name, * source method name and parameter, using the given resource bundle to * localize the message. If {@code bundleName} is null, the empty string * or not valid then the message is not localized. * * @param logLevel * the level of the given message. * @param sourceClass * the source class name. * @param sourceMethod * the source method name. * @param bundleName * the name of the resource bundle used to localize the message. * @param msg * the message to be logged. * @param param * the parameter associated with the event that is logged. */ public void logrb(Level logLevel, String sourceClass, String sourceMethod, String bundleName, String msg, Object param) { if (!internalIsLoggable(logLevel)) { return; } LogRecord record = new LogRecord(logLevel, msg); if (bundleName != null) { try { record.setResourceBundle(loadResourceBundle(bundleName)); } catch (MissingResourceException e) { // ignore } record.setResourceBundleName(bundleName); } record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); record.setParameters(new Object[] { param }); log(record); } /** * Logs a message of the given level with the specified source class name, * source method name and parameter array, using the given resource bundle * to localize the message. If {@code bundleName} is null, the empty string * or not valid then the message is not localized. * * @param logLevel * the level of the given message. * @param sourceClass * the source class name. * @param sourceMethod * the source method name. * @param bundleName * the name of the resource bundle used to localize the message. * @param msg * the message to be logged. * @param params * the parameter array associated with the event that is logged. */ public void logrb(Level logLevel, String sourceClass, String sourceMethod, String bundleName, String msg, Object[] params) { if (!internalIsLoggable(logLevel)) { return; } LogRecord record = new LogRecord(logLevel, msg); if (bundleName != null) { try { record.setResourceBundle(loadResourceBundle(bundleName)); } catch (MissingResourceException e) { // ignore } record.setResourceBundleName(bundleName); } record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); record.setParameters(params); log(record); } /** * Logs a message of the given level with the specified source class name, * source method name and {@code Throwable} object, using the given resource * bundle to localize the message. If {@code bundleName} is null, the empty * string or not valid then the message is not localized. * * @param logLevel * the level of the given message * @param sourceClass * the source class name * @param sourceMethod * the source method name * @param bundleName * the name of the resource bundle used to localize the message. * @param msg * the message to be logged. * @param thrown * the {@code Throwable} object. */ public void logrb(Level logLevel, String sourceClass, String sourceMethod, String bundleName, String msg, Throwable thrown) { if (!internalIsLoggable(logLevel)) { return; } LogRecord record = new LogRecord(logLevel, msg); if (bundleName != null) { try { record.setResourceBundle(loadResourceBundle(bundleName)); } catch (MissingResourceException e) { // ignore } record.setResourceBundleName(bundleName); } record.setLoggerName(this.name); record.setSourceClassName(sourceClass); record.setSourceMethodName(sourceMethod); record.setThrown(thrown); log(record); } void reset() { levelObjVal = null; levelIntVal = Level.INFO.intValue(); for (Handler handler : handlers) { try { if (handlers.remove(handler)) { handler.close(); } } catch (Exception ignored) { } } updateDalvikLogHandler(); } }