All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.slf4j.LoggerFactory Maven / Gradle / Ivy

/**
 * Copyright (c) 2004-2011 QOS.ch
 * All rights reserved.
 *
 * Permission is hereby granted, free  of charge, to any person obtaining
 * a  copy  of this  software  and  associated  documentation files  (the
 * "Software"), to  deal in  the Software without  restriction, including
 * without limitation  the rights to  use, copy, modify,  merge, publish,
 * distribute,  sublicense, and/or sell  copies of  the Software,  and to
 * permit persons to whom the Software  is furnished to do so, subject to
 * the following conditions:
 *
 * The  above  copyright  notice  and  this permission  notice  shall  be
 * included in all copies or substantial portions of the Software.
 *
 * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
 * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
 * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
package org.slf4j;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;

import org.slf4j.event.SubstituteLoggingEvent;
import org.slf4j.helpers.NOPLoggerFactory;
import org.slf4j.helpers.SubstituteLogger;
import org.slf4j.helpers.SubstituteLoggerFactory;
import org.slf4j.helpers.Util;
import org.slf4j.impl.StaticLoggerBinder;

/**
 * The LoggerFactory 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.
 * 

*

* LoggerFactory is essentially a wrapper around an * {@link ILoggerFactory} instance bound with LoggerFactory at * compile time. *

*

* Please note that all methods in LoggerFactory are static. * * * @author Alexander Dorokhine * @author Robert Elliot * @author Ceki Gülcü * */ public final class LoggerFactory { static final String CODES_PREFIX = "http://www.slf4j.org/codes.html"; 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 in failed state. Original exception was thrown EARLIER. See also " + UNSUCCESSFUL_INIT_URL; static final int UNINITIALIZED = 0; static final int ONGOING_INITIALIZATION = 1; static final int FAILED_INITIALIZATION = 2; static final int SUCCESSFUL_INITIALIZATION = 3; static final int NOP_FALLBACK_INITIALIZATION = 4; static volatile int INITIALIZATION_STATE = UNINITIALIZED; static final SubstituteLoggerFactory SUBST_FACTORY = new SubstituteLoggerFactory(); static final NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory(); // Support for detecting mismatched logger names. static final String DETECT_LOGGER_NAME_MISMATCH_PROPERTY = "slf4j.detectLoggerNameMismatch"; static final String JAVA_VENDOR_PROPERTY = "java.vendor.url"; static boolean DETECT_LOGGER_NAME_MISMATCH = Util.safeGetBooleanSystemProperty(DETECT_LOGGER_NAME_MISMATCH_PROPERTY); /** * It is LoggerFactory's responsibility to track version changes and manage * the compatibility list. *

*

* It is assumed that all versions in the 1.6 are mutually compatible. */ static private final String[] API_COMPATIBILITY_LIST = new String[] { "1.6", "1.7" }; // private constructor prevents instantiation private LoggerFactory() { } /** * Force LoggerFactory to consider itself uninitialized. *

*

* 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. *

*

* You are strongly discouraged from calling this method in production code. */ static void reset() { INITIALIZATION_STATE = UNINITIALIZED; } private final static void performInitialization() { bind(); if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) { versionSanityCheck(); } } private static boolean messageContainsOrgSlf4jImplStaticLoggerBinder(String msg) { if (msg == null) return false; if (msg.contains("org/slf4j/impl/StaticLoggerBinder")) return true; if (msg.contains("org.slf4j.impl.StaticLoggerBinder")) return true; return false; } private final static void bind() { try { Set staticLoggerBinderPathSet = null; // skip check under android, see also // http://jira.qos.ch/browse/SLF4J-328 if (!isAndroid()) { staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet(); reportMultipleBindingAmbiguity(staticLoggerBinderPathSet); } // the next line does the binding StaticLoggerBinder.getSingleton(); INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION; reportActualBinding(staticLoggerBinderPathSet); } 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."); } else { failedBinding(ncde); throw ncde; } } catch (java.lang.NoSuchMethodError nsme) { String msg = nsme.getMessage(); if (msg != null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) { 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."); } throw nsme; } catch (Exception e) { failedBinding(e); throw new IllegalStateException("Unexpected initialization failure", e); } finally { postBindCleanUp(); } } private static void postBindCleanUp() { fixSubstituteLoggers(); replayEvents(); // release all resources in SUBST_FACTORY SUBST_FACTORY.clear(); } private static void fixSubstituteLoggers() { synchronized (SUBST_FACTORY) { SUBST_FACTORY.postInitialization(); for (SubstituteLogger substLogger : SUBST_FACTORY.getLoggers()) { Logger logger = getLogger(substLogger.getName()); substLogger.setDelegate(logger); } } } static void failedBinding(Throwable t) { INITIALIZATION_STATE = FAILED_INITIALIZATION; Util.report("Failed to instantiate SLF4J LoggerFactory", t); } private static void replayEvents() { final LinkedBlockingQueue queue = SUBST_FACTORY.getEventQueue(); final int queueSize = queue.size(); int count = 0; final int maxDrain = 128; List 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()) { substLogger.log(event); } else { Util.report(loggerName); } } private static void emitSubstitutionWarning() { 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); } private static void emitReplayWarning(int eventCount) { Util.report("A number (" + eventCount + ") of logging calls during the initialization phase have been intercepted and are"); Util.report("now being replayed. These are subject to the filtering rules of the underlying logging system."); Util.report("See also " + REPLAY_URL); } private final static void versionSanityCheck() { try { String requested = StaticLoggerBinder.REQUESTED_API_VERSION; boolean match = false; for (String aAPI_COMPATIBILITY_LIST : API_COMPATIBILITY_LIST) { if (requested.startsWith(aAPI_COMPATIBILITY_LIST)) { 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"; static Set findPossibleStaticLoggerBinderPathSet() { // use Set instead of list in order to deal with bug #138 // LinkedHashSet appropriate here because it preserves insertion order // during iteration Set staticLoggerBinderPathSet = new LinkedHashSet(); try { ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader(); Enumeration paths; if (loggerFactoryClassLoader == null) { paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH); } else { paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH); } while (paths.hasMoreElements()) { URL path = paths.nextElement(); staticLoggerBinderPathSet.add(path); } } catch (IOException ioe) { Util.report("Error getting resources from path", ioe); } return staticLoggerBinderPathSet; } private static boolean isAmbiguousStaticLoggerBinderPathSet(Set binderPathSet) { return binderPathSet.size() > 1; } /** * 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 binderPathSet) { if (isAmbiguousStaticLoggerBinderPathSet(binderPathSet)) { Util.report("Class path contains multiple SLF4J bindings."); for (URL path : binderPathSet) { Util.report("Found binding in [" + path + "]"); } Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation."); } } private static boolean isAndroid() { String vendor = Util.safeGetSystemProperty(JAVA_VENDOR_PROPERTY); if (vendor == null) return false; return vendor.toLowerCase().contains("android"); } private static void reportActualBinding(Set binderPathSet) { // binderPathSet can be null under Android if (binderPathSet != null && isAmbiguousStaticLoggerBinderPathSet(binderPathSet)) { Util.report("Actual binding is of type [" + StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr() + "]"); } } /** * Return a logger named according to the name parameter using the * statically bound {@link ILoggerFactory} instance. * * @param name * The name of the logger. * @return logger */ public static Logger getLogger(String name) { ILoggerFactory iLoggerFactory = getILoggerFactory(); return iLoggerFactory.getLogger(name); } /** * Return a logger named corresponding to the class passed as parameter, * using the statically bound {@link ILoggerFactory} instance. * *

* In case the the clazz 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 * slf4j.detectLoggerNameMismatch 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 * @return logger * * * @see Detected * logger name mismatch */ public static Logger getLogger(Class clazz) { Logger logger = getLogger(clazz.getName()); if (DETECT_LOGGER_NAME_MISMATCH) { Class autoComputedCallingClass = Util.getCallingClass(); if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) { Util.report(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"); } } return logger; } private static boolean nonMatchingClasses(Class clazz, Class autoComputedCallingClass) { return !autoComputedCallingClass.isAssignableFrom(clazz); } /** * Return the {@link ILoggerFactory} instance in use. *

*

* ILoggerFactory instance is bound with this class at compile time. * * @return the ILoggerFactory instance in use */ public static ILoggerFactory getILoggerFactory() { if (INITIALIZATION_STATE == UNINITIALIZED) { synchronized (LoggerFactory.class) { if (INITIALIZATION_STATE == UNINITIALIZED) { INITIALIZATION_STATE = ONGOING_INITIALIZATION; performInitialization(); } } } switch (INITIALIZATION_STATE) { case SUCCESSFUL_INITIALIZATION: return StaticLoggerBinder.getSingleton().getLoggerFactory(); case NOP_FALLBACK_INITIALIZATION: return NOP_FALLBACK_FACTORY; case FAILED_INITIALIZATION: throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG); case ONGOING_INITIALIZATION: // support re-entrant behavior. // See also http://jira.qos.ch/browse/SLF4J-97 return SUBST_FACTORY; } throw new IllegalStateException("Unreachable code"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy