/* * 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. */ // Contibutors: Alex Blewitt <Alex.Blewitt@ioshq.com> // Markus Oestreicher <oes@zurich.ibm.com> // Frank Hoering <fhr@zurich.ibm.com> // Nelson Minar <nelson@media.mit.edu> // Jim Cakalic <jim_cakalic@na.biomerieux.com> // Avy Sharell <asharell@club-internet.fr> // Ciaran Treanor <ciaran@xelector.com> // Jeff Turner <jeff@socialchange.net.au> // Michael Horwitz <MHorwitz@siemens.co.za> // Calvin Chan <calvin.chan@hic.gov.au> // Aaron Greenhouse <aarong@cs.cmu.edu> // Beat Meier <bmeier@infovia.com.ar> // Colin Sampaleanu <colinml1@exis.com> package org.apache.log4j; import java.util.Enumeration; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Vector; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.log4j.helpers.AppenderAttachableImpl; import org.apache.log4j.helpers.NullEnumeration; import org.apache.log4j.spi.AppenderAttachable; import org.apache.log4j.spi.HierarchyEventListener; import org.apache.log4j.spi.LoggerRepository; import org.apache.log4j.spi.LoggingEvent; /** * <font color="#AA2222"><b>This class has been deprecated and replaced by the {@link Logger} <em>subclass</em></b></font>. It will be kept * around to preserve backward compatibility until mid 2003. * * <p> * <code>Logger</code> is a subclass of Category, i.e. it extends Category. In other words, a logger <em>is</em> a category. Thus, all * operations that can be performed on a category can be performed on a logger. Internally, whenever log4j is asked to produce a Category * object, it will instead produce a Logger object. Log4j 1.2 will <em>never</em> produce Category objects but only <code>Logger</code> * instances. In order to preserve backward compatibility, methods that previously accepted category objects still continue to accept * category objects. * * <p> * For example, the following are all legal and will work as expected. * * <pre> *    // Deprecated form: *    Category cat = Category.getInstance("foo.bar") * *    // Preferred form for retrieving loggers: *    Logger logger = Logger.getLogger("foo.bar") * </pre> * * <p> * The first form is deprecated and should be avoided. * * <p> * <b>There is absolutely no need for new client code to use or refer to the <code>Category</code> class.</b> Whenever possible, please * avoid referring to it or using it. * * <p> * See the <a href="../../../../manual.html">short manual</a> for an introduction on this class. * <p> * See the document entitled <a href="http://www.qos.ch/logging/preparingFor13.html">preparing for log4j 1.3</a> for a more detailed * discussion. * * @author Ceki Gülcü * @author Anders Kristensen */ public class Category implements AppenderAttachable { /** * The hierarchy where categories are attached to by default. */ // static // public // final Hierarchy defaultHierarchy = new Hierarchy(new // RootCategory(Level.DEBUG)); /** * The name of this category. */ protected String name; /** * The assigned level of this category. The <code>level</code> variable need not be assigned a value in which case it is inherited form * the hierarchy. */ volatile protected Level level; /** * The parent of this category. All categories have at least one ancestor which is the root category. */ volatile protected Category parent; /** * The fully qualified name of the Category class. See also the getFQCN method. */ private static final String FQCN = Category.class.getName(); private ReadWriteLock lock = new ReentrantReadWriteLock(); protected ResourceBundle resourceBundle; // Categories need to know what Hierarchy they are in protected LoggerRepository repository; AppenderAttachableImpl aai; /** * Additivity is set to true by default, that is children inherit the appenders of their ancestors by default. If this variable is set * to <code>false</code> then the appenders found in the ancestors of this category are not used. However, the children of this category * will inherit its appenders, unless the children have their additivity flag set to <code>false</code> too. See the user manual for * more details. */ protected boolean additive = true; /** * This constructor created a new <code>Category</code> instance and sets its name. * * <p> * It is intended to be used by sub-classes only. You should not create categories directly. * * @param name The name of the category. */ protected Category(String name) { this.name = name; } /** * Add <code>newAppender</code> to the list of appenders of this Category instance. * * <p> * If <code>newAppender</code> is already in the list of appenders, then it won't be added again. */ public void addAppender(Appender newAppender) { lock.writeLock().lock(); try { if (aai == null) { aai = new AppenderAttachableImpl(); } aai.addAppender(newAppender); repository.fireAddAppenderEvent(this, newAppender); } finally { lock.writeLock().unlock(); } } /** * If <code>assertion</code> parameter is <code>false</code>, then logs <code>msg</code> as an {@link #error(Object) error} statement. * * <p> * The <code>assert</code> method has been renamed to <code>assertLog</code> because <code>assert</code> is a language reserved word in * JDK 1.4. * * @param assertion * @param msg The message to print if <code>assertion</code> is false. * @since 1.2 */ public void assertLog(boolean assertion, String msg) { if (!assertion) this.error(msg); } /** * Call the appenders in the hierrachy starting at <code>this</code>. If no appenders could be found, emit a warning. * * <p> * This method calls all the appenders inherited from the hierarchy circumventing any evaluation of whether to log or not to log the * particular log request. * * @param event the event to log. */ public void callAppenders(LoggingEvent event) { int writes = 0; for (Category c = this; c != null; c = c.parent) { // Protected against simultaneous call to addAppender, removeAppender,... c.lock.readLock().lock(); try { if (c.aai != null) { writes += c.aai.appendLoopOnAppenders(event); } if (!c.additive) { break; } } finally { c.lock.readLock().unlock(); } } if (writes == 0) { repository.emitNoAppenderWarning(this); } } /** * Close all attached appenders implementing the AppenderAttachable interface. * * @since 1.0 */ void closeNestedAppenders() { // shouldn't readLock() be enough? lock.writeLock().lock(); try { Enumeration enumeration = this.getAllAppenders(); if (enumeration != null) { while (enumeration.hasMoreElements()) { Appender a = (Appender) enumeration.nextElement(); if (a instanceof AppenderAttachable) { a.close(); } } } } finally { lock.writeLock().unlock(); } } /** * Log a message object with the {@link Level#DEBUG DEBUG} level. * * <p> * This method first checks if this category is <code>DEBUG</code> enabled by comparing the level of this category with the * {@link Level#DEBUG DEBUG} level. If this category is <code>DEBUG</code> enabled, then it converts the message object (passed as * parameter) to a string by invoking the appropriate {@link org.apache.log4j.or.ObjectRenderer}. It then proceeds to call all the * registered appenders in this category and also higher in the hierarchy depending on the value of the additivity flag. * * <p> * <b>WARNING</b> Note that passing a {@link Throwable} to this method will print the name of the <code>Throwable</code> but no stack * trace. To print a stack trace use the {@link #debug(Object, Throwable)} form instead. * * @param message the message object to log. */ public void debug(Object message) { if (repository.isDisabled(Level.DEBUG_INT)) return; if (Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) { forcedLog(FQCN, Level.DEBUG, message, null); } } /** * Log a message object with the <code>DEBUG</code> level including the stack trace of the {@link Throwable} <code>t</code> passed as * parameter. * * <p> * See {@link #debug(Object)} form for more detailed information. * * @param message the message object to log. * @param t the exception to log, including its stack trace. */ public void debug(Object message, Throwable t) { if (repository.isDisabled(Level.DEBUG_INT)) return; if (Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, Level.DEBUG, message, t); } /** * Log a message object with the {@link Level#ERROR ERROR} Level. * * <p> * This method first checks if this category is <code>ERROR</code> enabled by comparing the level of this category with * {@link Level#ERROR ERROR} Level. If this category is <code>ERROR</code> enabled, then it converts the message object passed as * parameter to a string by invoking the appropriate {@link org.apache.log4j.or.ObjectRenderer}. It proceeds to call all the registered * appenders in this category and also higher in the hierarchy depending on the value of the additivity flag. * * <p> * <b>WARNING</b> Note that passing a {@link Throwable} to this method will print the name of the <code>Throwable</code> but no stack * trace. To print a stack trace use the {@link #error(Object, Throwable)} form instead. * * @param message the message object to log */ public void error(Object message) { if (repository.isDisabled(Level.ERROR_INT)) return; if (Level.ERROR.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, Level.ERROR, message, null); } /** * Log a message object with the <code>ERROR</code> level including the stack trace of the {@link Throwable} <code>t</code> passed as * parameter. * * <p> * See {@link #error(Object)} form for more detailed information. * * @param message the message object to log. * @param t the exception to log, including its stack trace. */ public void error(Object message, Throwable t) { if (repository.isDisabled(Level.ERROR_INT)) return; if (Level.ERROR.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, Level.ERROR, message, t); } /** * If the named category exists (in the default hierarchy) then it returns a reference to the category, otherwise it returns * <code>null</code>. * * @deprecated Please use {@link LogManager#exists} instead. * @since 0.8.5 */ public static Logger exists(String name) { return LogManager.exists(name); } /** * Log a message object with the {@link Level#FATAL FATAL} Level. * * <p> * This method first checks if this category is <code>FATAL</code> enabled by comparing the level of this category with * {@link Level#FATAL FATAL} Level. If the category is <code>FATAL</code> enabled, then it converts the message object passed as * parameter to a string by invoking the appropriate {@link org.apache.log4j.or.ObjectRenderer}. It proceeds to call all the registered * appenders in this category and also higher in the hierarchy depending on the value of the additivity flag. * * <p> * <b>WARNING</b> Note that passing a {@link Throwable} to this method will print the name of the Throwable but no stack trace. To print * a stack trace use the {@link #fatal(Object, Throwable)} form instead. * * @param message the message object to log */ public void fatal(Object message) { if (repository.isDisabled(Level.FATAL_INT)) return; if (Level.FATAL.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, Level.FATAL, message, null); } /** * Log a message object with the <code>FATAL</code> level including the stack trace of the {@link Throwable} <code>t</code> passed as * parameter. * * <p> * See {@link #fatal(Object)} for more detailed information. * * @param message the message object to log. * @param t the exception to log, including its stack trace. */ public void fatal(Object message, Throwable t) { if (repository.isDisabled(Level.FATAL_INT)) return; if (Level.FATAL.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, Level.FATAL, message, t); } /** * This method creates a new logging event and logs the event without further checks. */ protected void forcedLog(String fqcn, Priority level, Object message, Throwable t) { callAppenders(new LoggingEvent(fqcn, this, level, message, t)); } /** * Get the additivity flag for this Category instance. */ public boolean getAdditivity() { return additive; } /** * Get the appenders contained in this category as an {@link Enumeration}. If no appenders can be found, then a {@link NullEnumeration} * is returned. * * @return Enumeration An enumeration of the appenders in this category. */ public Enumeration getAllAppenders() { lock.readLock().lock(); try { if (aai == null) return NullEnumeration.getInstance(); else return aai.getAllAppenders(); } finally { lock.readLock().unlock(); } } /** * Look for the appender named as <code>name</code>. * * <p> * Return the appender with that name if in the list. Return <code>null</code> otherwise. */ public Appender getAppender(String name) { lock.readLock().lock(); try { if (aai == null || name == null) return null; return aai.getAppender(name); } finally { lock.readLock().unlock(); } } /** * Starting from this category, search the category hierarchy for a non-null level and return it. Otherwise, return the level of the * root category. * * <p> * The Category class is designed so that this method executes as quickly as possible. */ public Level getEffectiveLevel() { for (Category c = this; c != null; c = c.parent) { if (c.level != null) return c.level; } return null; // If reached will cause an NullPointerException. } /** * * @deprecated Please use the the {@link #getEffectiveLevel} method instead. * */ public Priority getChainedPriority() { for (Category c = this; c != null; c = c.parent) { if (c.level != null) return c.level; } return null; // If reached will cause an NullPointerException. } /** * Returns all the currently defined categories in the default hierarchy as an {@link java.util.Enumeration Enumeration}. * * <p> * The root category is <em>not</em> included in the returned {@link Enumeration}. * * @deprecated Please use {@link LogManager#getCurrentLoggers()} instead. */ public static Enumeration getCurrentCategories() { return LogManager.getCurrentLoggers(); } /** * Return the default Hierarchy instance. * * @deprecated Please use {@link LogManager#getLoggerRepository()} instead. * @since 1.0 */ public static LoggerRepository getDefaultHierarchy() { return LogManager.getLoggerRepository(); } /** * Return the the {@link Hierarchy} where this <code>Category</code> instance is attached. * * @deprecated Please use {@link #getLoggerRepository} instead. * @since 1.1 */ public LoggerRepository getHierarchy() { return repository; } /** * Return the the {@link LoggerRepository} where this <code>Category</code> is attached. * * @since 1.2 */ public LoggerRepository getLoggerRepository() { return repository; } /** * @deprecated Make sure to use {@link Logger#getLogger(String)} instead. */ public static Category getInstance(String name) { return LogManager.getLogger(name); } /** * @deprecated Please make sure to use {@link Logger#getLogger(Class)} instead. */ public static Category getInstance(Class clazz) { return LogManager.getLogger(clazz); } /** * Return the category name. */ public final String getName() { return name; } /** * Returns the parent of this category. Note that the parent of a given category may change during the lifetime of the category. * * <p> * The root category will return <code>null</code>. * * @since 1.2 */ final public Category getParent() { return this.parent; } /** * Returns the assigned {@link Level}, if any, for this Category. * * @return Level - the assigned Level, can be <code>null</code>. */ final public Level getLevel() { return this.level; } /** * @deprecated Please use {@link #getLevel} instead. */ final public Level getPriority() { return this.level; } /** * @deprecated Please use {@link Logger#getRootLogger()} instead. */ final public static Category getRoot() { return LogManager.getRootLogger(); } /** * Return the <em>inherited</em> {@link ResourceBundle} for this category. * * <p> * This method walks the hierarchy to find the appropriate resource bundle. It will return the resource bundle attached to the closest * ancestor of this category, much like the way priorities are searched. In case there is no bundle in the hierarchy then * <code>null</code> is returned. * * @since 0.9.0 */ public ResourceBundle getResourceBundle() { for (Category c = this; c != null; c = c.parent) { if (c.resourceBundle != null) return c.resourceBundle; } // It might be the case that there is no resource bundle return null; } /** * Returns the string resource coresponding to <code>key</code> in this category's inherited resource bundle. See also * {@link #getResourceBundle}. * * <p> * If the resource cannot be found, then an {@link #error error} message will be logged complaining about the missing resource. */ protected String getResourceBundleString(String key) { ResourceBundle rb = getResourceBundle(); // This is one of the rare cases where we can use logging in order // to report errors from within log4j. if (rb == null) { // if(!hierarchy.emittedNoResourceBundleWarning) { // error("No resource bundle has been set for category "+name); // hierarchy.emittedNoResourceBundleWarning = true; // } return null; } else { try { return rb.getString(key); } catch (MissingResourceException mre) { error("No resource is associated with key \"" + key + "\"."); return null; } } } /** * Log a message object with the {@link Level#INFO INFO} Level. * * <p> * This method first checks if this category is <code>INFO</code> enabled by comparing the level of this category with * {@link Level#INFO INFO} Level. If the category is <code>INFO</code> enabled, then it converts the message object passed as parameter * to a string by invoking the appropriate {@link org.apache.log4j.or.ObjectRenderer}. It proceeds to call all the registered appenders * in this category and also higher in the hierarchy depending on the value of the additivity flag. * * <p> * <b>WARNING</b> Note that passing a {@link Throwable} to this method will print the name of the Throwable but no stack trace. To print * a stack trace use the {@link #info(Object, Throwable)} form instead. * * @param message the message object to log */ public void info(Object message) { if (repository.isDisabled(Level.INFO_INT)) return; if (Level.INFO.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, Level.INFO, message, null); } /** * Log a message object with the <code>INFO</code> level including the stack trace of the {@link Throwable} <code>t</code> passed as * parameter. * * <p> * See {@link #info(Object)} for more detailed information. * * @param message the message object to log. * @param t the exception to log, including its stack trace. */ public void info(Object message, Throwable t) { if (repository.isDisabled(Level.INFO_INT)) return; if (Level.INFO.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, Level.INFO, message, t); } /** * Is the appender passed as parameter attached to this category? */ public boolean isAttached(Appender appender) { if (appender == null || aai == null) return false; else { return aai.isAttached(appender); } } /** * Check whether this category is enabled for the <code>DEBUG</code> Level. * * <p> * This function is intended to lessen the computational cost of disabled log debug statements. * * <p> * For some <code>cat</code> Category object, when you write, * * <pre> * cat.debug("This is entry number: " + i); * </pre> * * <p> * You incur the cost constructing the message, concatenatiion in this case, regardless of whether the message is logged or not. * * <p> * If you are worried about speed, then you should write * * <pre> * if (cat.isDebugEnabled()) { * cat.debug("This is entry number: " + i); * } * </pre> * * <p> * This way you will not incur the cost of parameter construction if debugging is disabled for <code>cat</code>. On the other hand, if * the <code>cat</code> is debug enabled, you will incur the cost of evaluating whether the category is debug enabled twice. Once in * <code>isDebugEnabled</code> and once in the <code>debug</code>. This is an insignificant overhead since evaluating a category takes * about 1%% of the time it takes to actually log. * * @return boolean - <code>true</code> if this category is debug enabled, <code>false</code> otherwise. * */ public boolean isDebugEnabled() { if (repository.isDisabled(Level.DEBUG_INT)) return false; return Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel()); } /** * Check whether this category is enabled for a given {@link Level} passed as parameter. * * See also {@link #isDebugEnabled}. * * @return boolean True if this category is enabled for <code>level</code>. */ public boolean isEnabledFor(Priority level) { if (repository.isDisabled(level.level)) return false; return level.isGreaterOrEqual(this.getEffectiveLevel()); } /** * Check whether this category is enabled for the info Level. See also {@link #isDebugEnabled}. * * @return boolean - <code>true</code> if this category is enabled for level info, <code>false</code> otherwise. */ public boolean isInfoEnabled() { if (repository.isDisabled(Level.INFO_INT)) return false; return Level.INFO.isGreaterOrEqual(this.getEffectiveLevel()); } /** * Log a localized message. The user supplied parameter <code>key</code> is replaced by its localized version from the resource bundle. * * @see #setResourceBundle * @since 0.8.4 */ public void l7dlog(Priority priority, String key, Throwable t) { if (repository.isDisabled(priority.level)) { return; } if (priority.isGreaterOrEqual(this.getEffectiveLevel())) { String msg = getResourceBundleString(key); // if message corresponding to 'key' could not be found in the // resource bundle, then default to 'key'. if (msg == null) { msg = key; } forcedLog(FQCN, priority, msg, t); } } /** * Log a localized and parameterized message. First, the user supplied <code>key</code> is searched in the resource bundle. Next, the * resulting pattern is formatted using {@link java.text.MessageFormat#format(String,Object[])} method with the user supplied object * array <code>params</code>. * * @since 0.8.4 */ public void l7dlog(Priority priority, String key, Object[] params, Throwable t) { if (repository.isDisabled(priority.level)) { return; } if (priority.isGreaterOrEqual(this.getEffectiveLevel())) { String pattern = getResourceBundleString(key); String msg; if (pattern == null) msg = key; else msg = java.text.MessageFormat.format(pattern, params); forcedLog(FQCN, priority, msg, t); } } /** * This generic form is intended to be used by wrappers. */ public void log(Priority priority, Object message, Throwable t) { if (repository.isDisabled(priority.level)) { return; } if (priority.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, priority, message, t); } /** * This generic form is intended to be used by wrappers. */ public void log(Priority priority, Object message) { if (repository.isDisabled(priority.level)) { return; } if (priority.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, priority, message, null); } /** * This is the most generic printing method. It is intended to be invoked by <b>wrapper</b> classes. * * @param callerFQCN The wrapper class' fully qualified class name. * @param level The level of the logging request. * @param message The message of the logging request. * @param t The throwable of the logging request, may be null. */ public void log(String callerFQCN, Priority level, Object message, Throwable t) { if (repository.isDisabled(level.level)) { return; } if (level.isGreaterOrEqual(this.getEffectiveLevel())) { forcedLog(callerFQCN, level, message, t); } } /** * LoggerRepository forgot the fireRemoveAppenderEvent method, if using the stock Hierarchy implementation, then call its fireRemove. * Custom repositories can implement HierarchyEventListener if they want remove notifications. * * @param appender appender, may be null. */ private void fireRemoveAppenderEvent(final Appender appender) { if (appender != null) { if (repository instanceof Hierarchy) { ((Hierarchy) repository).fireRemoveAppenderEvent(this, appender); } else if (repository instanceof HierarchyEventListener) { ((HierarchyEventListener) repository).removeAppenderEvent(this, appender); } } } /** * Remove all previously added appenders from this Category instance. * * <p> * This is useful when re-reading configuration information. */ public void removeAllAppenders() { lock.writeLock().lock(); try { if (aai != null) { Vector appenders = new Vector(); for (Enumeration iter = aai.getAllAppenders(); iter != null && iter.hasMoreElements();) { appenders.add(iter.nextElement()); } aai.removeAllAppenders(); for (Enumeration iter = appenders.elements(); iter.hasMoreElements();) { fireRemoveAppenderEvent((Appender) iter.nextElement()); } aai = null; } } finally { lock.writeLock().unlock(); } } /** * Remove the appender passed as parameter form the list of appenders. * * @since 0.8.2 */ public void removeAppender(Appender appender) { lock.writeLock().lock(); try { if (appender == null || aai == null) return; boolean wasAttached = aai.isAttached(appender); aai.removeAppender(appender); if (wasAttached) { fireRemoveAppenderEvent(appender); } } finally { lock.writeLock().unlock(); } } /** * Remove the appender with the name passed as parameter form the list of appenders. * * @since 0.8.2 */ public void removeAppender(String name) { lock.writeLock().lock(); try { if (name == null || aai == null) return; Appender appender = aai.getAppender(name); aai.removeAppender(name); if (appender != null) { fireRemoveAppenderEvent(appender); } } finally { lock.writeLock().unlock(); } } /** * Set the additivity flag for this Category instance. * * @since 0.8.1 */ public void setAdditivity(boolean additive) { this.additive = additive; } /** * Only the Hiearchy class can set the hiearchy of a category. Default package access is MANDATORY here. */ final void setHierarchy(LoggerRepository repository) { this.repository = repository; } /** * Set the level of this Category. If you are passing any of <code>Level.DEBUG</code>, <code>Level.INFO</code>, <code>Level.WARN</code>, * <code>Level.ERROR</code>, <code>Level.FATAL</code> as a parameter, you need to case them as Level. * * <p> * As in * * <pre> * logger.setLevel((Level) Level.DEBUG); * </pre> * * * <p> * Null values are admitted. */ public void setLevel(Level level) { this.level = level; } /** * Set the level of this Category. * * <p> * Null values are admitted. * * @deprecated Please use {@link #setLevel} instead. */ public void setPriority(Priority priority) { this.level = (Level) priority; } /** * Set the resource bundle to be used with localized logging methods {@link #l7dlog(Priority,String,Throwable)} and * {@link #l7dlog(Priority,String,Object[],Throwable)}. * * @since 0.8.4 */ public void setResourceBundle(ResourceBundle bundle) { resourceBundle = bundle; } /** * Calling this method will <em>safely</em> close and remove all appenders in all the categories including root contained in the default * hierachy. * * <p> * Some appenders such as {@link org.apache.log4j.net.SocketAppender} and {@link AsyncAppender} need to be closed before the application * exists. Otherwise, pending logging events might be lost. * * <p> * The <code>shutdown</code> method is careful to close nested appenders before closing regular appenders. This is allows configurations * where a regular appender is attached to a category and again to a nested appender. * * @deprecated Please use {@link LogManager#shutdown()} instead. * @since 1.0 */ public static void shutdown() { LogManager.shutdown(); } /** * Log a message object with the {@link Level#WARN WARN} Level. * * <p> * This method first checks if this category is <code>WARN</code> enabled by comparing the level of this category with * {@link Level#WARN WARN} Level. If the category is <code>WARN</code> enabled, then it converts the message object passed as parameter * to a string by invoking the appropriate {@link org.apache.log4j.or.ObjectRenderer}. It proceeds to call all the registered appenders * in this category and also higher in the hieararchy depending on the value of the additivity flag. * * <p> * <b>WARNING</b> Note that passing a {@link Throwable} to this method will print the name of the Throwable but no stack trace. To print * a stack trace use the {@link #warn(Object, Throwable)} form instead. * <p> * * @param message the message object to log. */ public void warn(Object message) { if (repository.isDisabled(Level.WARN_INT)) return; if (Level.WARN.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, Level.WARN, message, null); } /** * Log a message with the <code>WARN</code> level including the stack trace of the {@link Throwable} <code>t</code> passed as parameter. * * <p> * See {@link #warn(Object)} for more detailed information. * * @param message the message object to log. * @param t the exception to log, including its stack trace. */ public void warn(Object message, Throwable t) { if (repository.isDisabled(Level.WARN_INT)) return; if (Level.WARN.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, Level.WARN, message, t); } }