View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.log4j;
    19
    20  import org.apache.log4j.spi.LoggerRepository;
    21  import org.apache.log4j.spi.LoggerFactory;
    22  import org.apache.log4j.spi.RepositorySelector;
    23  import org.apache.log4j.spi.DefaultRepositorySelector;
    24  import org.apache.log4j.spi.RootLogger;
    25  import org.apache.log4j.spi.NOPLoggerRepository;
    26  import org.apache.log4j.helpers.Loader;
    27  import org.apache.log4j.helpers.OptionConverter;
    28  import org.apache.log4j.helpers.LogLog;
    29
    30  import java.net.URL;
    31  import java.net.MalformedURLException;
    32
    33
    34  import java.util.Enumeration;
    35  import java.io.StringWriter;
    36  import java.io.PrintWriter;
    37
    38  /**
    39   * Use the <code>LogManager</code> class to retreive {@link Logger}
    40   * instances or to operate on the current {@link
    41   * LoggerRepository}. When the <code>LogManager</code> class is loaded
    42   * into memory the default initalzation procedure is inititated. The
    43   * default intialization procedure</a> is described in the <a
    44   * href="../../../../manual.html#defaultInit">short log4j manual</a>.
    45   *
    46   * @author Ceki G&uuml;lc&uuml; */
    47  public class LogManager {
    48
    49    /**
    50     * @deprecated This variable is for internal use only. It will
    51     * become package protected in future versions.
    52     * */
    53    static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
    54
    55    static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";
    56
    57    /**
    58     * @deprecated This variable is for internal use only. It will
    59     * become private in future versions.
    60     * */
    61    static final public String DEFAULT_CONFIGURATION_KEY="log4j.configuration";
    62
    63    /**
    64     * @deprecated This variable is for internal use only. It will
    65     * become private in future versions.
    66     * */
    67    static final public String CONFIGURATOR_CLASS_KEY="log4j.configuratorClass";
    68
    69    /**
    70    * @deprecated This variable is for internal use only. It will
    71    * become private in future versions.
    72    */
    73    public static final String DEFAULT_INIT_OVERRIDE_KEY =
    74                                                   "log4j.defaultInitOverride";
    75
    76
    77    static private Object guard = null;
    78    static private RepositorySelector repositorySelector;
    79
    80    static {
    81      // By default we use a DefaultRepositorySelector which always returns 'h'.
    82      Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
    83      repositorySelector = new DefaultRepositorySelector(h);
    84
    85      /** Search for the properties file log4j.properties in the CLASSPATH.  */
    86      String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
    87  						       null);
    88
    89      // if there is no default init override, then get the resource
    90      // specified by the user or the default config file.
    91      if(override == null || "false".equalsIgnoreCase(override)) {
    92
    93        String configurationOptionStr = OptionConverter.getSystemProperty(
    94  							  DEFAULT_CONFIGURATION_KEY,
    95  							  null);
    96
    97        String configuratorClassName = OptionConverter.getSystemProperty(
    98                                                     CONFIGURATOR_CLASS_KEY,
    99  						   null);
    100
    101       URL url = null;
    102
    103       // if the user has not specified the log4j.configuration
    104       // property, we search first for the file "log4j.xml" and then
    105       // "log4j.properties"
    106       if(configurationOptionStr == null) {
    107 	url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
    108 	if(url == null) {
    109 	  url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
    110 	}
    111       } else {
    112 	try {
    113 	  url = new URL(configurationOptionStr);
    114 	} catch (MalformedURLException ex) {
    115 	  // so, resource is not a URL:
    116 	  // attempt to get the resource from the class path
    117 	  url = Loader.getResource(configurationOptionStr);
    118 	}
    119       }
    120
    121       // If we have a non-null url, then delegate the rest of the
    122       // configuration to the OptionConverter.selectAndConfigure
    123       // method.
    124       if(url != null) {
    125 	    LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
    126         try {
    127             OptionConverter.selectAndConfigure(url, configuratorClassName,
    128 					   LogManager.getLoggerRepository());
    129         } catch (NoClassDefFoundError e) {
    130             LogLog.warn("Error during default initialization", e);
    131         }
    132       } else {
    133 	    LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
    134       }
    135     } else {
    136         LogLog.debug("Default initialization of overridden by " +
    137             DEFAULT_INIT_OVERRIDE_KEY + "property.");
    138     }
    139   }
    140
    141   /**
    142      Sets <code>LoggerFactory</code> but only if the correct
    143      <em>guard</em> is passed as parameter.
    144
    145      <p>Initally the guard is null.  If the guard is
    146      <code>null</code>, then invoking this method sets the logger
    147      factory and the guard. Following invocations will throw a {@link
    148      IllegalArgumentException}, unless the previously set
    149      <code>guard</code> is passed as the second parameter.
    150
    151      <p>This allows a high-level component to set the {@link
    152      RepositorySelector} used by the <code>LogManager</code>.
    153
    154      <p>For example, when tomcat starts it will be able to install its
    155      own repository selector. However, if and when Tomcat is embedded
    156      within JBoss, then JBoss will install its own repository selector
    157      and Tomcat will use the repository selector set by its container,
    158      JBoss.  */
    159   static
    160   public
    161   void setRepositorySelector(RepositorySelector selector, Object guard)
    162                                                  throws IllegalArgumentException {
    163     if((LogManager.guard != null) && (LogManager.guard != guard)) {
    164       throw new IllegalArgumentException(
    165            "Attempted to reset the LoggerFactory without possessing the guard.");
    166     }
    167
    168     if(selector == null) {
    169       throw new IllegalArgumentException("RepositorySelector must be non-null.");
    170     }
    171
    172     LogManager.guard = guard;
    173     LogManager.repositorySelector = selector;
    174   }
    175
    176
    177     /**
    178      * This method tests if called from a method that
    179      * is known to result in class members being abnormally
    180      * set to null but is assumed to be harmless since the
    181      * all classes are in the process of being unloaded.
    182      *
    183      * @param ex exception used to determine calling stack.
    184      * @return true if calling stack is recognized as likely safe.
    185      */
    186   private static boolean isLikelySafeScenario(final Exception ex) {
    187       StringWriter stringWriter = new StringWriter();
    188       ex.printStackTrace(new PrintWriter(stringWriter));
    189       String msg = stringWriter.toString();
    190       return msg.indexOf("org.apache.catalina.loader.WebappClassLoader.stop") != -1;
    191   }
    192
    193   static
    194   public
    195   LoggerRepository getLoggerRepository() {
    196     if (repositorySelector == null) {
    197         repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
    198         guard = null;
    199         Exception ex = new IllegalStateException("Class invariant violation");
    200         String msg =
    201                 "log4j called after unloading, see http://logging.apache.org/log4j/1.2/faq.html#unload.";
    202         if (isLikelySafeScenario(ex)) {
    203             LogLog.debug(msg, ex);
    204         } else {
    205             LogLog.error(msg, ex);
    206         }
    207     }
    208     return repositorySelector.getLoggerRepository();
    209   }
    210
    211   /**
    212      Retrieve the appropriate root logger.
    213    */
    214   public
    215   static
    216   Logger getRootLogger() {
    217      // Delegate the actual manufacturing of the logger to the logger repository.
    218     return getLoggerRepository().getRootLogger();
    219   }
    220
    221   /**
    222      Retrieve the appropriate {@link Logger} instance.
    223   */
    224   public
    225   static
    226   Logger getLogger(final String name) {
    227      // Delegate the actual manufacturing of the logger to the logger repository.
    228     return getLoggerRepository().getLogger(name);
    229   }
    230
    231  /**
    232      Retrieve the appropriate {@link Logger} instance.
    233   */
    234   public
    235   static
    236   Logger getLogger(final Class clazz) {
    237      // Delegate the actual manufacturing of the logger to the logger repository.
    238     return getLoggerRepository().getLogger(clazz.getName());
    239   }
    240
    241
    242   /**
    243      Retrieve the appropriate {@link Logger} instance.
    244   */
    245   public
    246   static
    247   Logger getLogger(final String name, final LoggerFactory factory) {
    248      // Delegate the actual manufacturing of the logger to the logger repository.
    249     return getLoggerRepository().getLogger(name, factory);
    250   }
    251
    252   public
    253   static
    254   Logger exists(final String name) {
    255     return getLoggerRepository().exists(name);
    256   }
    257
    258   public
    259   static
    260   Enumeration getCurrentLoggers() {
    261     return getLoggerRepository().getCurrentLoggers();
    262   }
    263
    264   public
    265   static
    266   void shutdown() {
    267     getLoggerRepository().shutdown();
    268   }
    269
    270   public
    271   static
    272   void resetConfiguration() {
    273     getLoggerRepository().resetConfiguration();
    274   }
    275 }
    276