001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.log4j; 019 020import org.apache.log4j.spi.LoggerRepository; 021import org.apache.log4j.spi.LoggerFactory; 022import org.apache.log4j.spi.RepositorySelector; 023import org.apache.log4j.spi.DefaultRepositorySelector; 024import org.apache.log4j.spi.RootLogger; 025import org.apache.log4j.spi.NOPLoggerRepository; 026import org.apache.log4j.helpers.Loader; 027import org.apache.log4j.helpers.OptionConverter; 028import org.apache.log4j.helpers.LogLog; 029 030import java.net.URL; 031import java.net.MalformedURLException; 032 033 034import java.util.Enumeration; 035import java.io.StringWriter; 036import java.io.PrintWriter; 037 038/** 039 * Use the <code>LogManager</code> class to retreive {@link Logger} 040 * instances or to operate on the current {@link 041 * LoggerRepository}. When the <code>LogManager</code> class is loaded 042 * into memory the default initalzation procedure is inititated. The 043 * default intialization procedure</a> is described in the <a 044 * href="../../../../manual.html#defaultInit">short log4j manual</a>. 045 * 046 * @author Ceki Gülcü */ 047public class LogManager { 048 049 /** 050 * @deprecated This variable is for internal use only. It will 051 * become package protected in future versions. 052 * */ 053 static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties"; 054 055 static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml"; 056 057 /** 058 * @deprecated This variable is for internal use only. It will 059 * become private in future versions. 060 * */ 061 static final public String DEFAULT_CONFIGURATION_KEY="log4j.configuration"; 062 063 /** 064 * @deprecated This variable is for internal use only. It will 065 * become private in future versions. 066 * */ 067 static final public String CONFIGURATOR_CLASS_KEY="log4j.configuratorClass"; 068 069 /** 070 * @deprecated This variable is for internal use only. It will 071 * become private in future versions. 072 */ 073 public static final String DEFAULT_INIT_OVERRIDE_KEY = 074 "log4j.defaultInitOverride"; 075 076 077 static private Object guard = null; 078 static private RepositorySelector repositorySelector; 079 080 static { 081 // By default we use a DefaultRepositorySelector which always returns 'h'. 082 Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG)); 083 repositorySelector = new DefaultRepositorySelector(h); 084 085 /** Search for the properties file log4j.properties in the CLASSPATH. */ 086 String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY, 087 null); 088 089 // if there is no default init override, then get the resource 090 // specified by the user or the default config file. 091 if(override == null || "false".equalsIgnoreCase(override)) { 092 093 String configurationOptionStr = OptionConverter.getSystemProperty( 094 DEFAULT_CONFIGURATION_KEY, 095 null); 096 097 String configuratorClassName = OptionConverter.getSystemProperty( 098 CONFIGURATOR_CLASS_KEY, 099 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