aboutsummaryrefslogtreecommitdiff
path: root/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java
diff options
context:
space:
mode:
Diffstat (limited to 'slf4j-api/src/main/java/org/slf4j/LoggerFactory.java')
-rwxr-xr-xslf4j-api/src/main/java/org/slf4j/LoggerFactory.java467
1 files changed, 312 insertions, 155 deletions
diff --git a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java
index 2f74c18b..4e1f0b0d 100755
--- a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java
+++ b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java
@@ -25,34 +25,41 @@
package org.slf4j;
import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
-import org.slf4j.helpers.NOPLoggerFactory;
+import org.slf4j.event.SubstituteLoggingEvent;
+import org.slf4j.helpers.NOP_FallbackServiceProvider;
+import org.slf4j.helpers.Reporter;
import org.slf4j.helpers.SubstituteLogger;
-import org.slf4j.helpers.SubstituteLoggerFactory;
+import org.slf4j.helpers.SubstituteServiceProvider;
import org.slf4j.helpers.Util;
-import org.slf4j.impl.StaticLoggerBinder;
+import org.slf4j.spi.SLF4JServiceProvider;
/**
* The <code>LoggerFactory</code> is a utility class producing Loggers for
- * various logging APIs, most notably for log4j, logback and JDK 1.4 logging.
- * Other implementations such as {@link org.slf4j.impl.NOPLogger NOPLogger} and
- * {@link org.slf4j.impl.SimpleLogger SimpleLogger} are also supported.
- * <p/>
- * <p/>
- * <code>LoggerFactory</code> is essentially a wrapper around an
- * {@link ILoggerFactory} instance bound with <code>LoggerFactory</code> at
- * compile time.
- * <p/>
- * <p/>
- * Please note that all methods in <code>LoggerFactory</code> are static.
+ * various logging APIs, e.g. logback, reload4j, log4j and JDK 1.4 logging.
+ * Other implementations such as {@link org.slf4j.helpers.NOPLogger NOPLogger} and
+ * SimpleLogger are also supported.
+ *
+ * <p><code>LoggerFactory</code> is essentially a wrapper around an
+ * {@link ILoggerFactory} instance provided by a {@link SLF4JServiceProvider}.
*
+ * <p>
+ * Please note that all methods in <code>LoggerFactory</code> are static.
*
* @author Alexander Dorokhine
* @author Robert Elliot
@@ -61,17 +68,27 @@ import org.slf4j.impl.StaticLoggerBinder;
*/
public final class LoggerFactory {
- static final String CODES_PREFIX = "http://www.slf4j.org/codes.html";
+ static final String CODES_PREFIX = "https://www.slf4j.org/codes.html";
+
+ static final String NO_PROVIDERS_URL = CODES_PREFIX + "#noProviders";
+ static final String IGNORED_BINDINGS_URL = CODES_PREFIX + "#ignoredBindings";
- static final String NO_STATICLOGGERBINDER_URL = CODES_PREFIX + "#StaticLoggerBinder";
static final String MULTIPLE_BINDINGS_URL = CODES_PREFIX + "#multiple_bindings";
- static final String NULL_LF_URL = CODES_PREFIX + "#null_LF";
static final String VERSION_MISMATCH = CODES_PREFIX + "#version_mismatch";
static final String SUBSTITUTE_LOGGER_URL = CODES_PREFIX + "#substituteLogger";
static final String LOGGER_NAME_MISMATCH_URL = CODES_PREFIX + "#loggerNameMismatch";
+ static final String REPLAY_URL = CODES_PREFIX + "#replay";
static final String UNSUCCESSFUL_INIT_URL = CODES_PREFIX + "#unsuccessfulInit";
- static final String UNSUCCESSFUL_INIT_MSG = "org.slf4j.LoggerFactory could not be successfully initialized. See also " + UNSUCCESSFUL_INIT_URL;
+ static final String UNSUCCESSFUL_INIT_MSG = "org.slf4j.LoggerFactory in failed state. Original exception was thrown EARLIER. See also "
+ + UNSUCCESSFUL_INIT_URL;
+ /**
+ * System property for explicitly setting the provider class. If set and the provider could be instantiated,
+ * then the service loading mechanism will be bypassed.
+ *
+ * @since 2.0.9
+ */
+ static final public String PROVIDER_PROPERTY_KEY = "slf4j.provider";
static final int UNINITIALIZED = 0;
static final int ONGOING_INITIALIZATION = 1;
@@ -79,22 +96,69 @@ public final class LoggerFactory {
static final int SUCCESSFUL_INITIALIZATION = 3;
static final int NOP_FALLBACK_INITIALIZATION = 4;
- static int INITIALIZATION_STATE = UNINITIALIZED;
- static SubstituteLoggerFactory TEMP_FACTORY = new SubstituteLoggerFactory();
- static NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory();
+ static volatile int INITIALIZATION_STATE = UNINITIALIZED;
+ static final SubstituteServiceProvider SUBST_PROVIDER = new SubstituteServiceProvider();
+ static final NOP_FallbackServiceProvider NOP_FALLBACK_SERVICE_PROVIDER = new NOP_FallbackServiceProvider();
// Support for detecting mismatched logger names.
static final String DETECT_LOGGER_NAME_MISMATCH_PROPERTY = "slf4j.detectLoggerNameMismatch";
- static boolean DETECT_LOGGER_NAME_MISMATCH = Boolean.getBoolean(DETECT_LOGGER_NAME_MISMATCH_PROPERTY);
+ static final String JAVA_VENDOR_PROPERTY = "java.vendor.url";
+
+ static boolean DETECT_LOGGER_NAME_MISMATCH = Util.safeGetBooleanSystemProperty(DETECT_LOGGER_NAME_MISMATCH_PROPERTY);
+
+ static volatile SLF4JServiceProvider PROVIDER;
+
+ // Package access for tests
+ static List<SLF4JServiceProvider> findServiceProviders() {
+ List<SLF4JServiceProvider> providerList = new ArrayList<>();
+
+ // retain behaviour similar to that of 1.7 series and earlier. More specifically, use the class loader that
+ // loaded the present class to search for services
+ final ClassLoader classLoaderOfLoggerFactory = LoggerFactory.class.getClassLoader();
+
+ SLF4JServiceProvider explicitProvider = loadExplicitlySpecified(classLoaderOfLoggerFactory);
+ if(explicitProvider != null) {
+ providerList.add(explicitProvider);
+ return providerList;
+ }
+
+
+ ServiceLoader<SLF4JServiceProvider> serviceLoader = getServiceLoader(classLoaderOfLoggerFactory);
+
+ Iterator<SLF4JServiceProvider> iterator = serviceLoader.iterator();
+ while (iterator.hasNext()) {
+ safelyInstantiate(providerList, iterator);
+ }
+ return providerList;
+ }
+
+ private static ServiceLoader<SLF4JServiceProvider> getServiceLoader(final ClassLoader classLoaderOfLoggerFactory) {
+ ServiceLoader<SLF4JServiceProvider> serviceLoader;
+ SecurityManager securityManager = System.getSecurityManager();
+ if(securityManager == null) {
+ serviceLoader = ServiceLoader.load(SLF4JServiceProvider.class, classLoaderOfLoggerFactory);
+ } else {
+ final PrivilegedAction<ServiceLoader<SLF4JServiceProvider>> action = () -> ServiceLoader.load(SLF4JServiceProvider.class, classLoaderOfLoggerFactory);
+ serviceLoader = AccessController.doPrivileged(action);
+ }
+ return serviceLoader;
+ }
+
+ private static void safelyInstantiate(List<SLF4JServiceProvider> providerList, Iterator<SLF4JServiceProvider> iterator) {
+ try {
+ SLF4JServiceProvider provider = iterator.next();
+ providerList.add(provider);
+ } catch (ServiceConfigurationError e) {
+ Reporter.error("A service provider failed to instantiate:\n" + e.getMessage());
+ }
+ }
/**
* It is LoggerFactory's responsibility to track version changes and manage
* the compatibility list.
- * <p/>
- * <p/>
- * It is assumed that all versions in the 1.6 are mutually compatible.
+ * <p>
*/
- static private final String[] API_COMPATIBILITY_LIST = new String[] { "1.6", "1.7" };
+ static private final String[] API_COMPATIBILITY_LIST = new String[] { "2.0" };
// private constructor prevents instantiation
private LoggerFactory() {
@@ -102,18 +166,17 @@ public final class LoggerFactory {
/**
* Force LoggerFactory to consider itself uninitialized.
- * <p/>
- * <p/>
+ * <p>
+ * <p>
* This method is intended to be called by classes (in the same package) for
* testing purposes. This method is internal. It can be modified, renamed or
* removed at any time without notice.
- * <p/>
- * <p/>
+ * <p>
+ * <p>
* You are strongly discouraged from calling this method in production code.
*/
static void reset() {
INITIALIZATION_STATE = UNINITIALIZED;
- TEMP_FACTORY = new SubstituteLoggerFactory();
}
private final static void performInitialization() {
@@ -123,110 +186,77 @@ public final class LoggerFactory {
}
}
- private static boolean messageContainsOrgSlf4jImplStaticLoggerBinder(String msg) {
- if (msg == null)
- return false;
- if (msg.indexOf("org/slf4j/impl/StaticLoggerBinder") != -1)
- return true;
- if (msg.indexOf("org.slf4j.impl.StaticLoggerBinder") != -1)
- return true;
- return false;
- }
-
private final static void bind() {
try {
- Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
- reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
- // the next line does the binding
- StaticLoggerBinder.getSingleton();
- INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
- reportActualBinding(staticLoggerBinderPathSet);
- fixSubstitutedLoggers();
- } catch (NoClassDefFoundError ncde) {
- String msg = ncde.getMessage();
- if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
- INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
- Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
- Util.report("Defaulting to no-operation (NOP) logger implementation");
- Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
+ List<SLF4JServiceProvider> providersList = findServiceProviders();
+ reportMultipleBindingAmbiguity(providersList);
+ if (providersList != null && !providersList.isEmpty()) {
+ PROVIDER = providersList.get(0);
+ // SLF4JServiceProvider.initialize() is intended to be called here and nowhere else.
+ PROVIDER.initialize();
+ INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
+ reportActualBinding(providersList);
} else {
- failedBinding(ncde);
- throw ncde;
- }
- } catch (java.lang.NoSuchMethodError nsme) {
- String msg = nsme.getMessage();
- if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) {
- INITIALIZATION_STATE = FAILED_INITIALIZATION;
- Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
- Util.report("Your binding is version 1.5.5 or earlier.");
- Util.report("Upgrade your binding to version 1.6.x.");
+ INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
+ Reporter.warn("No SLF4J providers were found.");
+ Reporter.warn("Defaulting to no-operation (NOP) logger implementation");
+ Reporter.warn("See " + NO_PROVIDERS_URL + " for further details.");
+
+ Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
+ reportIgnoredStaticLoggerBinders(staticLoggerBinderPathSet);
}
- throw nsme;
+ postBindCleanUp();
} catch (Exception e) {
failedBinding(e);
throw new IllegalStateException("Unexpected initialization failure", e);
}
}
- static void failedBinding(Throwable t) {
- INITIALIZATION_STATE = FAILED_INITIALIZATION;
- Util.report("Failed to instantiate SLF4J LoggerFactory", t);
+ static SLF4JServiceProvider loadExplicitlySpecified(ClassLoader classLoader) {
+ String explicitlySpecified = System.getProperty(PROVIDER_PROPERTY_KEY);
+ if (null == explicitlySpecified || explicitlySpecified.isEmpty()) {
+ return null;
+ }
+ try {
+ String message = String.format("Attempting to load provider \"%s\" specified via \"%s\" system property", explicitlySpecified, PROVIDER_PROPERTY_KEY);
+ Reporter.info(message);
+ Class<?> clazz = classLoader.loadClass(explicitlySpecified);
+ Constructor<?> constructor = clazz.getConstructor();
+ Object provider = constructor.newInstance();
+ return (SLF4JServiceProvider) provider;
+ } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ String message = String.format("Failed to instantiate the specified SLF4JServiceProvider (%s)", explicitlySpecified);
+ Reporter.error(message, e);
+ return null;
+ } catch (ClassCastException e) {
+ String message = String.format("Specified SLF4JServiceProvider (%s) does not implement SLF4JServiceProvider interface", explicitlySpecified);
+ Reporter.error(message, e);
+ return null;
+ }
}
- private final static void fixSubstitutedLoggers() {
- List<SubstituteLogger> loggers = TEMP_FACTORY.getLoggers();
-
- if (loggers.isEmpty()) {
+ private static void reportIgnoredStaticLoggerBinders(Set<URL> staticLoggerBinderPathSet) {
+ if (staticLoggerBinderPathSet.isEmpty()) {
return;
}
+ Reporter.warn("Class path contains SLF4J bindings targeting slf4j-api versions 1.7.x or earlier.");
- Util.report("The following set of substitute loggers may have been accessed");
- Util.report("during the initialization phase. Logging calls during this");
- Util.report("phase were not honored. However, subsequent logging calls to these");
- Util.report("loggers will work as normally expected.");
- Util.report("See also " + SUBSTITUTE_LOGGER_URL);
- for (SubstituteLogger subLogger : loggers) {
- subLogger.setDelegate(getLogger(subLogger.getName()));
- Util.report(subLogger.getName());
+ for (URL path : staticLoggerBinderPathSet) {
+ Reporter.warn("Ignoring binding found at [" + path + "]");
}
+ Reporter.warn("See " + IGNORED_BINDINGS_URL + " for an explanation.");
- TEMP_FACTORY.clear();
- }
-
- private final static void versionSanityCheck() {
- try {
- String requested = StaticLoggerBinder.REQUESTED_API_VERSION;
-
- boolean match = false;
- for (int i = 0; i < API_COMPATIBILITY_LIST.length; i++) {
- if (requested.startsWith(API_COMPATIBILITY_LIST[i])) {
- match = true;
- }
- }
- if (!match) {
- Util.report("The requested version " + requested + " by your slf4j binding is not compatible with "
- + Arrays.asList(API_COMPATIBILITY_LIST).toString());
- Util.report("See " + VERSION_MISMATCH + " for further details.");
- }
- } catch (java.lang.NoSuchFieldError nsfe) {
- // given our large user base and SLF4J's commitment to backward
- // compatibility, we cannot cry here. Only for implementations
- // which willingly declare a REQUESTED_API_VERSION field do we
- // emit compatibility warnings.
- } catch (Throwable e) {
- // we should never reach here
- Util.report("Unexpected problem occured during version sanity check", e);
- }
}
- // We need to use the name of the StaticLoggerBinder class, but we can't reference
- // the class itself.
- private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
+ // We need to use the name of the StaticLoggerBinder class, but we can't
+ // reference the class itself.
+ private static final String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
- private static Set<URL> findPossibleStaticLoggerBinderPathSet() {
+ static Set<URL> findPossibleStaticLoggerBinderPathSet() {
// use Set instead of list in order to deal with bug #138
- // LinkedHashSet appropriate here because it preserves insertion order during iteration
- Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
+ // LinkedHashSet appropriate here because it preserves insertion order
+ // during iteration
+ Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<>();
try {
ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
Enumeration<URL> paths;
@@ -236,47 +266,155 @@ public final class LoggerFactory {
paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
}
while (paths.hasMoreElements()) {
- URL path = (URL) paths.nextElement();
+ URL path = paths.nextElement();
staticLoggerBinderPathSet.add(path);
}
} catch (IOException ioe) {
- Util.report("Error getting resources from path", ioe);
+ Reporter.error("Error getting resources from path", ioe);
}
return staticLoggerBinderPathSet;
}
- private static boolean isAmbiguousStaticLoggerBinderPathSet(Set<URL> staticLoggerBinderPathSet) {
- return staticLoggerBinderPathSet.size() > 1;
+ private static void postBindCleanUp() {
+ fixSubstituteLoggers();
+ replayEvents();
+ // release all resources in SUBST_FACTORY
+ SUBST_PROVIDER.getSubstituteLoggerFactory().clear();
+ }
+
+ private static void fixSubstituteLoggers() {
+ synchronized (SUBST_PROVIDER) {
+ SUBST_PROVIDER.getSubstituteLoggerFactory().postInitialization();
+ for (SubstituteLogger substLogger : SUBST_PROVIDER.getSubstituteLoggerFactory().getLoggers()) {
+ Logger logger = getLogger(substLogger.getName());
+ substLogger.setDelegate(logger);
+ }
+ }
+
+ }
+
+ static void failedBinding(Throwable t) {
+ INITIALIZATION_STATE = FAILED_INITIALIZATION;
+ Reporter.error("Failed to instantiate SLF4J LoggerFactory", t);
+ }
+
+ private static void replayEvents() {
+ final LinkedBlockingQueue<SubstituteLoggingEvent> queue = SUBST_PROVIDER.getSubstituteLoggerFactory().getEventQueue();
+ final int queueSize = queue.size();
+ int count = 0;
+ final int maxDrain = 128;
+ List<SubstituteLoggingEvent> eventList = new ArrayList<>(maxDrain);
+ while (true) {
+ int numDrained = queue.drainTo(eventList, maxDrain);
+ if (numDrained == 0)
+ break;
+ for (SubstituteLoggingEvent event : eventList) {
+ replaySingleEvent(event);
+ if (count++ == 0)
+ emitReplayOrSubstituionWarning(event, queueSize);
+ }
+ eventList.clear();
+ }
+ }
+
+ private static void emitReplayOrSubstituionWarning(SubstituteLoggingEvent event, int queueSize) {
+ if (event.getLogger().isDelegateEventAware()) {
+ emitReplayWarning(queueSize);
+ } else if (event.getLogger().isDelegateNOP()) {
+ // nothing to do
+ } else {
+ emitSubstitutionWarning();
+ }
+ }
+
+ private static void replaySingleEvent(SubstituteLoggingEvent event) {
+ if (event == null)
+ return;
+
+ SubstituteLogger substLogger = event.getLogger();
+ String loggerName = substLogger.getName();
+ if (substLogger.isDelegateNull()) {
+ throw new IllegalStateException("Delegate logger cannot be null at this state.");
+ }
+
+ if (substLogger.isDelegateNOP()) {
+ // nothing to do
+ } else if (substLogger.isDelegateEventAware()) {
+ if(substLogger.isEnabledForLevel(event.getLevel())) {
+ substLogger.log(event);
+ }
+ } else {
+ Reporter.warn(loggerName);
+ }
+ }
+
+ private static void emitSubstitutionWarning() {
+ Reporter.warn("The following set of substitute loggers may have been accessed");
+ Reporter.warn("during the initialization phase. Logging calls during this");
+ Reporter.warn("phase were not honored. However, subsequent logging calls to these");
+ Reporter.warn("loggers will work as normally expected.");
+ Reporter.warn("See also " + SUBSTITUTE_LOGGER_URL);
+ }
+
+ private static void emitReplayWarning(int eventCount) {
+ Reporter.warn("A number (" + eventCount + ") of logging calls during the initialization phase have been intercepted and are");
+ Reporter.warn("now being replayed. These are subject to the filtering rules of the underlying logging system.");
+ Reporter.warn("See also " + REPLAY_URL);
+ }
+
+ private final static void versionSanityCheck() {
+ try {
+ String requested = PROVIDER.getRequestedApiVersion();
+
+ boolean match = false;
+ for (String aAPI_COMPATIBILITY_LIST : API_COMPATIBILITY_LIST) {
+ if (requested.startsWith(aAPI_COMPATIBILITY_LIST)) {
+ match = true;
+ }
+ }
+ if (!match) {
+ Reporter.warn("The requested version " + requested + " by your slf4j provider is not compatible with "
+ + Arrays.asList(API_COMPATIBILITY_LIST).toString());
+ Reporter.warn("See " + VERSION_MISMATCH + " for further details.");
+ }
+ } catch (Throwable e) {
+ // we should never reach here
+ Reporter.error("Unexpected problem occurred during version sanity check", e);
+ }
+ }
+
+ private static boolean isAmbiguousProviderList(List<SLF4JServiceProvider> providerList) {
+ return providerList.size() > 1;
}
/**
- * Prints a warning message on the console if multiple bindings were found on the class path.
- * No reporting is done otherwise.
+ * Prints a warning message on the console if multiple bindings were found
+ * on the class path. No reporting is done otherwise.
*
*/
- private static void reportMultipleBindingAmbiguity(Set<URL> staticLoggerBinderPathSet) {
- if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) {
- Util.report("Class path contains multiple SLF4J bindings.");
- Iterator<URL> iterator = staticLoggerBinderPathSet.iterator();
- while (iterator.hasNext()) {
- URL path = (URL) iterator.next();
- Util.report("Found binding in [" + path + "]");
+ private static void reportMultipleBindingAmbiguity(List<SLF4JServiceProvider> providerList) {
+ if (isAmbiguousProviderList(providerList)) {
+ Reporter.warn("Class path contains multiple SLF4J providers.");
+ for (SLF4JServiceProvider provider : providerList) {
+ Reporter.warn("Found provider [" + provider + "]");
}
- Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
+ Reporter.warn("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
}
}
- private static void reportActualBinding(Set<URL> staticLoggerBinderPathSet) {
- if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) {
- Util.report("Actual binding is of type [" + StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr() + "]");
+ private static void reportActualBinding(List<SLF4JServiceProvider> providerList) {
+ // binderPathSet can be null under Android
+ if (!providerList.isEmpty() && isAmbiguousProviderList(providerList)) {
+ Reporter.info("Actual provider is of type [" + providerList.get(0) + "]");
}
}
/**
- * Return a logger named according to the name parameter using the statically
- * bound {@link ILoggerFactory} instance.
+ * Return a logger named according to the name parameter using the
+ * statically bound {@link ILoggerFactory} instance.
*
- * @param name The name of the logger.
+ * @param name
+ * The name of the logger.
* @return logger
*/
public static Logger getLogger(String name) {
@@ -285,29 +423,34 @@ public final class LoggerFactory {
}
/**
- * Return a logger named corresponding to the class passed as parameter, using
- * the statically bound {@link ILoggerFactory} instance.
+ * Return a logger named corresponding to the class passed as parameter,
+ * using the statically bound {@link ILoggerFactory} instance.
+ *
+ * <p>
+ * In case the <code>clazz</code> parameter differs from the name of the
+ * caller as computed internally by SLF4J, a logger name mismatch warning
+ * will be printed but only if the
+ * <code>slf4j.detectLoggerNameMismatch</code> system property is set to
+ * true. By default, this property is not set and no warnings will be
+ * printed even in case of a logger name mismatch.
*
- * <p>In case the the <code>clazz</code> parameter differs from the name of
- * the caller as computed internally by SLF4J, a logger name mismatch warning will be
- * printed but only if the <code>slf4j.detectLoggerNameMismatch</code> system property is
- * set to true. By default, this property is not set and no warnings will be printed
- * even in case of a logger name mismatch.
- *
- * @param clazz the returned logger will be named after clazz
+ * @param clazz
+ * the returned logger will be named after clazz
* @return logger
*
*
- * @see <a href="http://www.slf4j.org/codes.html#loggerNameMismatch">Detected logger name mismatch</a>
+ * @see <a
+ * href="http://www.slf4j.org/codes.html#loggerNameMismatch">Detected
+ * logger name mismatch</a>
*/
public static Logger getLogger(Class<?> clazz) {
Logger logger = getLogger(clazz.getName());
if (DETECT_LOGGER_NAME_MISMATCH) {
Class<?> autoComputedCallingClass = Util.getCallingClass();
- if (nonMatchingClasses(clazz, autoComputedCallingClass)) {
- Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(),
+ if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
+ Reporter.warn(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(),
autoComputedCallingClass.getName()));
- Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
+ Reporter.warn("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
}
}
return logger;
@@ -319,28 +462,42 @@ public final class LoggerFactory {
/**
* Return the {@link ILoggerFactory} instance in use.
- * <p/>
- * <p/>
+ * <p>
+ * <p>
* ILoggerFactory instance is bound with this class at compile time.
*
* @return the ILoggerFactory instance in use
*/
public static ILoggerFactory getILoggerFactory() {
+ return getProvider().getLoggerFactory();
+ }
+
+ /**
+ * Return the {@link SLF4JServiceProvider} in use.
+
+ * @return provider in use
+ * @since 1.8.0
+ */
+ static SLF4JServiceProvider getProvider() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
- INITIALIZATION_STATE = ONGOING_INITIALIZATION;
- performInitialization();
+ synchronized (LoggerFactory.class) {
+ if (INITIALIZATION_STATE == UNINITIALIZED) {
+ INITIALIZATION_STATE = ONGOING_INITIALIZATION;
+ performInitialization();
+ }
+ }
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION:
- return StaticLoggerBinder.getSingleton().getLoggerFactory();
+ return PROVIDER;
case NOP_FALLBACK_INITIALIZATION:
- return NOP_FALLBACK_FACTORY;
+ return NOP_FALLBACK_SERVICE_PROVIDER;
case FAILED_INITIALIZATION:
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITIALIZATION:
// support re-entrant behavior.
- // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
- return TEMP_FACTORY;
+ // See also http://jira.qos.ch/browse/SLF4J-97
+ return SUBST_PROVIDER;
}
throw new IllegalStateException("Unreachable code");
}