/*
* 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 org.googlecode.perftrace.log4j;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import org.googlecode.perftrace.log4j.helpers.Loader;
import org.googlecode.perftrace.log4j.helpers.LogLog;
import org.googlecode.perftrace.log4j.helpers.OptionConverter;
import org.googlecode.perftrace.log4j.spi.DefaultRepositorySelector;
import org.googlecode.perftrace.log4j.spi.LoggerFactory;
import org.googlecode.perftrace.log4j.spi.LoggerRepository;
import org.googlecode.perftrace.log4j.spi.NOPLoggerRepository;
import org.googlecode.perftrace.log4j.spi.RepositorySelector;
import org.googlecode.perftrace.log4j.spi.RootLogger;
/**
* Use the <code>LogManager</code> class to retreive {@link Logger} instances or
* to operate on the current {@link LoggerRepository}. When the
* <code>LogManager</code> class is loaded into memory the default initalzation
* procedure is inititated. The default intialization procedure</a> is described
* in the <a href="../../../../manual.html#defaultInit">short log4j manual</a>.
*
* @author Ceki Gülcü
*/
public class LogManager {
/**
* @deprecated This variable is for internal use only. It will become
* package protected in future versions.
* */
static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";
/**
* @deprecated This variable is for internal use only. It will become
* private in future versions.
* @Modified zhongfeng 修改默认的参数log4j.configuration到 perftrace.logcfg;
* */
static final public String DEFAULT_CONFIGURATION_KEY = "perftrace.logcfg";
/**
* @deprecated This variable is for internal use only. It will become
* private in future versions.
* */
static final public String CONFIGURATOR_CLASS_KEY = "log4j.configuratorClass";
/**
* @deprecated This variable is for internal use only. It will become
* private in future versions.
*/
public static final String DEFAULT_INIT_OVERRIDE_KEY = "log4j.defaultInitOverride";
static private Object guard = null;
static private RepositorySelector repositorySelector;
static {
// By default we use a DefaultRepositorySelector which always returns
// 'h'.
Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
repositorySelector = new DefaultRepositorySelector(h);
/** Search for the properties file log4j.properties in the CLASSPATH. */
String override = OptionConverter.getSystemProperty(
DEFAULT_INIT_OVERRIDE_KEY, null);
// if there is no default init override, then get the resource
// specified by the user or the default config file.
if (override == null || "false".equalsIgnoreCase(override)) {
String configurationOptionStr = OptionConverter.getSystemProperty(
DEFAULT_CONFIGURATION_KEY, null);
String configuratorClassName = OptionConverter.getSystemProperty(
CONFIGURATOR_CLASS_KEY, null);
URL url = null;
// if the user has not specified the log4j.configuration
// property, we search first for the file "log4j.xml" and then
// "log4j.properties"
if (configurationOptionStr == null) {
url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
if (url == null) {
url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
}
} else {
try {
url = new URL(configurationOptionStr);
} catch (MalformedURLException ex) {
// so, resource is not a URL:
// attempt to get the resource from the class path
url = Loader.getResource(configurationOptionStr);
}
}
// If we have a non-null url, then delegate the rest of the
// configuration to the OptionConverter.selectAndConfigure
// method.
if (url != null) {
LogLog.debug("Using URL [" + url
+ "] for automatic log4j configuration.");
try {
OptionConverter.selectAndConfigure(url,
configuratorClassName, LogManager
.getLoggerRepository());
} catch (NoClassDefFoundError e) {
LogLog.warn("Error during default initialization", e);
}
} else {
LogLog.debug("Could not find resource: ["
+ configurationOptionStr + "].");
}
} else {
LogLog.debug("Default initialization of overridden by "
+ DEFAULT_INIT_OVERRIDE_KEY + "property.");
}
}
/**
* Sets <code>LoggerFactory</code> but only if the correct <em>guard</em> is
* passed as parameter.
*
* <p>
* Initally the guard is null. If the guard is <code>null</code>, then
* invoking this method sets the logger factory and the guard. Following
* invocations will throw a {@link IllegalArgumentException}, unless the
* previously set <code>guard</code> is passed as the second parameter.
*
* <p>
* This allows a high-level component to set the {@link RepositorySelector}
* used by the <code>LogManager</code>.
*
* <p>
* For example, when tomcat starts it will be able to install its own
* repository selector. However, if and when Tomcat is embedded within
* JBoss, then JBoss will install its own repository selector and Tomcat
* will use the repository selector set by its container, JBoss.
*/
static public void setRepositorySelector(RepositorySelector selector,
Object guard) throws IllegalArgumentException {
if ((LogManager.guard != null) && (LogManager.guard != guard)) {
throw new IllegalArgumentException(
"Attempted to reset the LoggerFactory without possessing the guard.");
}
if (selector == null) {
throw new IllegalArgumentException(
"RepositorySelector must be non-null.");
}
LogManager.guard = guard;
LogManager.repositorySelector = selector;
}
/**
* This method tests if called from a method that is known to result in
* class members being abnormally set to null but is assumed to be harmless
* since the all classes are in the process of being unloaded.
*
* @param ex
* exception used to determine calling stack.
* @return true if calling stack is recognized as likely safe.
*/
private static boolean isLikelySafeScenario(final Exception ex) {
StringWriter stringWriter = new StringWriter();
ex.printStackTrace(new PrintWriter(stringWriter));
String msg = stringWriter.toString();
return msg.indexOf("org.apache.catalina.loader.WebappClassLoader.stop") != -1;
}
static public LoggerRepository getLoggerRepository() {
if (repositorySelector == null) {
repositorySelector = new DefaultRepositorySelector(
new NOPLoggerRepository());
guard = null;
Exception ex = new IllegalStateException(
"Class invariant violation");
String msg = "log4j called after unloading, see http://logging.apache.org/log4j/1.2/faq.html#unload.";
if (isLikelySafeScenario(ex)) {
LogLog.debug(msg, ex);
} else {
LogLog.error(msg, ex);
}
}
return repositorySelector.getLoggerRepository();
}
/**
* Retrieve the appropriate root logger.
*/
public static Logger getRootLogger() {
// Delegate the actual manufacturing of the logger to the logger
// repository.
return getLoggerRepository().getRootLogger();
}
/**
* Retrieve the appropriate {@link Logger} instance.
*/
public static Logger getLogger(final String name) {
// Delegate the actual manufacturing of the logger to the logger
// repository.
return getLoggerRepository().getLogger(name);
}
/**
* Retrieve the appropriate {@link Logger} instance.
*/
public static Logger getLogger(final Class clazz) {
// Delegate the actual manufacturing of the logger to the logger
// repository.
return getLoggerRepository().getLogger(clazz.getName());
}
/**
* Retrieve the appropriate {@link Logger} instance.
*/
public static Logger getLogger(final String name,
final LoggerFactory factory) {
// Delegate the actual manufacturing of the logger to the logger
// repository.
return getLoggerRepository().getLogger(name, factory);
}
public static Logger exists(final String name) {
return getLoggerRepository().exists(name);
}
public static Enumeration getCurrentLoggers() {
return getLoggerRepository().getCurrentLoggers();
}
public static void shutdown() {
getLoggerRepository().shutdown();
}
public static void resetConfiguration() {
getLoggerRepository().resetConfiguration();
}
}