diff options
Diffstat (limited to 'slf4j-api/src/main/java/org/slf4j/LoggerFactory.java')
-rwxr-xr-x | slf4j-api/src/main/java/org/slf4j/LoggerFactory.java | 467 |
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"); } |