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