diff --git a/LICENSE.txt b/LICENSE.txt index 315bd4979..1a3d05323 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2004-2017 QOS.ch +Copyright (c) 2004-2022 QOS.ch Sarl (Switzerland) All rights reserved. Permission is hereby granted, free of charge, to any person obtaining diff --git a/pom.xml b/pom.xml index 3013b606f..bce7aa281 100755 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,7 @@ 1.6.0 0.8.1 1.2.17 + 1.2.18.0 1.0.13 4.12 3.3 @@ -65,6 +66,7 @@ slf4j-nop slf4j-jdk14 slf4j-log4j12 + slf4j-reload4j slf4j-jcl slf4j-android slf4j-ext @@ -107,6 +109,12 @@ ${log4j.version} + + ch.qos.reload4j + reload4j + ${reload4j.version} + + ch.qos.cal10n cal10n-api diff --git a/slf4j-api/LICENSE.txt b/slf4j-api/LICENSE.txt index 508a27283..1a3d05323 100644 --- a/slf4j-api/LICENSE.txt +++ b/slf4j-api/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2004-2007 QOS.ch +Copyright (c) 2004-2022 QOS.ch Sarl (Switzerland) All rights reserved. Permission is hereby granted, free of charge, to any person obtaining diff --git a/slf4j-jcl/LICENSE.txt b/slf4j-jcl/LICENSE.txt index 508a27283..1a3d05323 100644 --- a/slf4j-jcl/LICENSE.txt +++ b/slf4j-jcl/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2004-2007 QOS.ch +Copyright (c) 2004-2022 QOS.ch Sarl (Switzerland) All rights reserved. Permission is hereby granted, free of charge, to any person obtaining diff --git a/slf4j-jdk14/LICENSE.txt b/slf4j-jdk14/LICENSE.txt index 508a27283..30812561e 100644 --- a/slf4j-jdk14/LICENSE.txt +++ b/slf4j-jdk14/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2004-2007 QOS.ch +Copyright (c) 2004-2022 QOS.ch Sarl All rights reserved. Permission is hereby granted, free of charge, to any person obtaining diff --git a/slf4j-log4j12/LICENSE.txt b/slf4j-log4j12/LICENSE.txt index 508a27283..1a3d05323 100644 --- a/slf4j-log4j12/LICENSE.txt +++ b/slf4j-log4j12/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2004-2007 QOS.ch +Copyright (c) 2004-2022 QOS.ch Sarl (Switzerland) All rights reserved. Permission is hereby granted, free of charge, to any person obtaining diff --git a/slf4j-nop/LICENSE.txt b/slf4j-nop/LICENSE.txt index 508a27283..bdfc03e45 100644 --- a/slf4j-nop/LICENSE.txt +++ b/slf4j-nop/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2004-2007 QOS.ch +Copyright (c) 2004-2022 QOS.ch All rights reserved. Permission is hereby granted, free of charge, to any person obtaining diff --git a/slf4j-reload4j/LICENSE.txt b/slf4j-reload4j/LICENSE.txt new file mode 100644 index 000000000..508a27283 --- /dev/null +++ b/slf4j-reload4j/LICENSE.txt @@ -0,0 +1,24 @@ +Copyright (c) 2004-2007 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. + + + diff --git a/slf4j-reload4j/pom.xml b/slf4j-reload4j/pom.xml new file mode 100755 index 000000000..c7d1504df --- /dev/null +++ b/slf4j-reload4j/pom.xml @@ -0,0 +1,41 @@ + + + + 4.0.0 + + + org.slf4j + slf4j-parent + 1.7.32-SNAPSHOT + + + slf4j-reload4j + + jar + SLF4J Reload4j Binding + SLF4J Reload4j Binding + http://reload4j.qos.ch + + + + org.slf4j + slf4j-api + + + + ch.qos.reload4j + reload4j + + + + org.slf4j + slf4j-api + test-jar + ${project.version} + test + + + + + diff --git a/slf4j-reload4j/src/main/java/org/slf4j/impl/Reload4jLoggerAdapter.java b/slf4j-reload4j/src/main/java/org/slf4j/impl/Reload4jLoggerAdapter.java new file mode 100755 index 000000000..11b7ddaad --- /dev/null +++ b/slf4j-reload4j/src/main/java/org/slf4j/impl/Reload4jLoggerAdapter.java @@ -0,0 +1,617 @@ +/** + * 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.impl; + +import static org.slf4j.event.EventConstants.NA_SUBST; + +import java.io.Serializable; + +import org.apache.log4j.Level; +import org.apache.log4j.spi.LocationInfo; +import org.apache.log4j.spi.ThrowableInformation; +import org.slf4j.Logger; +import org.slf4j.Marker; +import org.slf4j.event.LoggingEvent; +import org.slf4j.helpers.FormattingTuple; +import org.slf4j.helpers.MarkerIgnoringBase; +import org.slf4j.helpers.MessageFormatter; +import org.slf4j.spi.LocationAwareLogger; + +/** + * A wrapper over {@link org.apache.log4j.Logger org.apache.log4j.Logger} in + * conforming to the {@link Logger} interface. + * + *

+ * Note that the logging levels mentioned in this class refer to those defined + * in the + * org.apache.log4j.Level class. + * + *

+ * The TRACE level was introduced in log4j version 1.2.12. In order to avoid + * crashing the host application, in the case the log4j version in use predates + * 1.2.12, the TRACE level will be mapped as DEBUG. See also SLF4J-59. + * + * @author Ceki Gülcü + * @since 1.7.33 + */ +public final class Reload4jLoggerAdapter extends MarkerIgnoringBase implements LocationAwareLogger, Serializable { + + private static final long serialVersionUID = 6182834493563598289L; + + final transient org.apache.log4j.Logger logger; + + /** + * Following the pattern discussed in pages 162 through 168 of "The complete + * log4j manual". + */ + final static String FQCN = Reload4jLoggerAdapter.class.getName(); + + // WARN: Log4jLoggerAdapter constructor should have only package access so + // that only Log4jLoggerFactory be able to create one. + Reload4jLoggerAdapter(org.apache.log4j.Logger logger) { + this.logger = logger; + this.name = logger.getName(); + } + + /** + * Is this logger instance enabled for the TRACE level? + * + * @return True if this Logger is enabled for level TRACE, false otherwise. + */ + public boolean isTraceEnabled() { + return logger.isTraceEnabled(); + } + + /** + * Log a message object at level TRACE. + * + * @param msg + * - the message object to be logged + */ + public void trace(String msg) { + logger.log(FQCN, Level.TRACE, msg, null); + } + + /** + * Log a message at level TRACE according to the specified format and + * argument. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for level TRACE. + *

+ * + * @param format + * the format string + * @param arg + * the argument + */ + public void trace(String format, Object arg) { + if (isTraceEnabled()) { + FormattingTuple ft = MessageFormatter.format(format, arg); + logger.log(FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level TRACE according to the specified format and + * arguments. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the TRACE level. + *

+ * + * @param format + * the format string + * @param arg1 + * the first argument + * @param arg2 + * the second argument + */ + public void trace(String format, Object arg1, Object arg2) { + if (isTraceEnabled()) { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + logger.log(FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level TRACE according to the specified format and + * arguments. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the TRACE level. + *

+ * + * @param format + * the format string + * @param arguments + * an array of arguments + */ + public void trace(String format, Object... arguments) { + if (isTraceEnabled()) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); + logger.log(FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at level TRACE with an accompanying message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + public void trace(String msg, Throwable t) { + logger.log(FQCN, Level.TRACE, msg, t); + } + + /** + * Is this logger instance enabled for the DEBUG level? + * + * @return True if this Logger is enabled for level DEBUG, false otherwise. + */ + public boolean isDebugEnabled() { + return logger.isDebugEnabled(); + } + + /** + * Log a message object at level DEBUG. + * + * @param msg + * - the message object to be logged + */ + public void debug(String msg) { + logger.log(FQCN, Level.DEBUG, msg, null); + } + + /** + * Log a message at level DEBUG according to the specified format and + * argument. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for level DEBUG. + *

+ * + * @param format + * the format string + * @param arg + * the argument + */ + public void debug(String format, Object arg) { + if (logger.isDebugEnabled()) { + FormattingTuple ft = MessageFormatter.format(format, arg); + logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level DEBUG according to the specified format and + * arguments. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the DEBUG level. + *

+ * + * @param format + * the format string + * @param arg1 + * the first argument + * @param arg2 + * the second argument + */ + public void debug(String format, Object arg1, Object arg2) { + if (logger.isDebugEnabled()) { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level DEBUG according to the specified format and + * arguments. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the DEBUG level. + *

+ * + * @param format + * the format string + * @param arguments an array of arguments + */ + public void debug(String format, Object... arguments) { + if (logger.isDebugEnabled()) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); + logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at level DEBUG with an accompanying message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + public void debug(String msg, Throwable t) { + logger.log(FQCN, Level.DEBUG, msg, t); + } + + /** + * Is this logger instance enabled for the INFO level? + * + * @return True if this Logger is enabled for the INFO level, false otherwise. + */ + public boolean isInfoEnabled() { + return logger.isInfoEnabled(); + } + + /** + * Log a message object at the INFO level. + * + * @param msg + * - the message object to be logged + */ + public void info(String msg) { + logger.log(FQCN, Level.INFO, msg, null); + } + + /** + * Log a message at level INFO according to the specified format and argument. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the INFO level. + *

+ * + * @param format + * the format string + * @param arg + * the argument + */ + public void info(String format, Object arg) { + if (logger.isInfoEnabled()) { + FormattingTuple ft = MessageFormatter.format(format, arg); + logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at the INFO level according to the specified format and + * arguments. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the INFO level. + *

+ * + * @param format + * the format string + * @param arg1 + * the first argument + * @param arg2 + * the second argument + */ + public void info(String format, Object arg1, Object arg2) { + if (logger.isInfoEnabled()) { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level INFO according to the specified format and + * arguments. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the INFO level. + *

+ * + * @param format + * the format string + * @param argArray + * an array of arguments + */ + public void info(String format, Object... argArray) { + if (logger.isInfoEnabled()) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at the INFO level with an accompanying + * message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + public void info(String msg, Throwable t) { + logger.log(FQCN, Level.INFO, msg, t); + } + + /** + * Is this logger instance enabled for the WARN level? + * + * @return True if this Logger is enabled for the WARN level, false otherwise. + */ + public boolean isWarnEnabled() { + return logger.isEnabledFor(Level.WARN); + } + + /** + * Log a message object at the WARN level. + * + * @param msg + * - the message object to be logged + */ + public void warn(String msg) { + logger.log(FQCN, Level.WARN, msg, null); + } + + /** + * Log a message at the WARN level according to the specified format and + * argument. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the WARN level. + *

+ * + * @param format + * the format string + * @param arg + * the argument + */ + public void warn(String format, Object arg) { + if (logger.isEnabledFor(Level.WARN)) { + FormattingTuple ft = MessageFormatter.format(format, arg); + logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at the WARN level according to the specified format and + * arguments. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the WARN level. + *

+ * + * @param format + * the format string + * @param arg1 + * the first argument + * @param arg2 + * the second argument + */ + public void warn(String format, Object arg1, Object arg2) { + if (logger.isEnabledFor(Level.WARN)) { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level WARN according to the specified format and + * arguments. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the WARN level. + *

+ * + * @param format + * the format string + * @param argArray + * an array of arguments + */ + public void warn(String format, Object... argArray) { + if (logger.isEnabledFor(Level.WARN)) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at the WARN level with an accompanying + * message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + public void warn(String msg, Throwable t) { + logger.log(FQCN, Level.WARN, msg, t); + } + + /** + * Is this logger instance enabled for level ERROR? + * + * @return True if this Logger is enabled for level ERROR, false otherwise. + */ + public boolean isErrorEnabled() { + return logger.isEnabledFor(Level.ERROR); + } + + /** + * Log a message object at the ERROR level. + * + * @param msg + * - the message object to be logged + */ + public void error(String msg) { + logger.log(FQCN, Level.ERROR, msg, null); + } + + /** + * Log a message at the ERROR level according to the specified format and + * argument. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the ERROR level. + *

+ * + * @param format + * the format string + * @param arg + * the argument + */ + public void error(String format, Object arg) { + if (logger.isEnabledFor(Level.ERROR)) { + FormattingTuple ft = MessageFormatter.format(format, arg); + logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at the ERROR level according to the specified format and + * arguments. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the ERROR level. + *

+ * + * @param format + * the format string + * @param arg1 + * the first argument + * @param arg2 + * the second argument + */ + public void error(String format, Object arg1, Object arg2) { + if (logger.isEnabledFor(Level.ERROR)) { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level ERROR according to the specified format and + * arguments. + * + *

+ * This form avoids superfluous object creation when the logger is disabled + * for the ERROR level. + *

+ * + * @param format + * the format string + * @param argArray + * an array of arguments + */ + public void error(String format, Object... argArray) { + if (logger.isEnabledFor(Level.ERROR)) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at the ERROR level with an accompanying + * message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + public void error(String msg, Throwable t) { + logger.log(FQCN, Level.ERROR, msg, t); + } + + public void log(Marker marker, String callerFQCN, int level, String msg, Object[] argArray, Throwable t) { + Level log4jLevel = toLog4jLevel(level); + logger.log(callerFQCN, log4jLevel, msg, t); + } + + private Level toLog4jLevel(int level) { + Level log4jLevel; + switch (level) { + case LocationAwareLogger.TRACE_INT: + log4jLevel = Level.TRACE; + break; + case LocationAwareLogger.DEBUG_INT: + log4jLevel = Level.DEBUG; + break; + case LocationAwareLogger.INFO_INT: + log4jLevel = Level.INFO; + break; + case LocationAwareLogger.WARN_INT: + log4jLevel = Level.WARN; + break; + case LocationAwareLogger.ERROR_INT: + log4jLevel = Level.ERROR; + break; + default: + throw new IllegalStateException("Level number " + level + " is not recognized."); + } + return log4jLevel; + } + + public void log(LoggingEvent event) { + Level log4jLevel = toLog4jLevel(event.getLevel().toInt()); + if (!logger.isEnabledFor(log4jLevel)) + return; + + org.apache.log4j.spi.LoggingEvent log4jevent = toLog4jEvent(event, log4jLevel); + logger.callAppenders(log4jevent); + + } + + private org.apache.log4j.spi.LoggingEvent toLog4jEvent(LoggingEvent event, Level log4jLevel) { + + FormattingTuple ft = MessageFormatter.format(event.getMessage(), event.getArgumentArray(), event.getThrowable()); + + LocationInfo locationInfo = new LocationInfo(NA_SUBST, NA_SUBST, NA_SUBST, "0"); + + ThrowableInformation ti = null; + Throwable t = ft.getThrowable(); + if (t != null) + ti = new ThrowableInformation(t); + + org.apache.log4j.spi.LoggingEvent log4jEvent = new org.apache.log4j.spi.LoggingEvent(FQCN, logger, event.getTimeStamp(), log4jLevel, ft.getMessage(), + event.getThreadName(), ti, null, locationInfo, null); + + return log4jEvent; + } + +} diff --git a/slf4j-reload4j/src/main/java/org/slf4j/impl/Reload4jLoggerFactory.java b/slf4j-reload4j/src/main/java/org/slf4j/impl/Reload4jLoggerFactory.java new file mode 100644 index 000000000..90cd66e72 --- /dev/null +++ b/slf4j-reload4j/src/main/java/org/slf4j/impl/Reload4jLoggerFactory.java @@ -0,0 +1,91 @@ +/** + * 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.impl; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.apache.log4j.LogManager; +import org.slf4j.ILoggerFactory; +import org.slf4j.Logger; +import org.slf4j.helpers.Util; + +/** + * Log4jLoggerFactory is an implementation of {@link ILoggerFactory} returning + * the appropriate named {@link Reload4jLoggerAdapter} instance. + * + * @author Ceki Gülcü + * @since 1.7.33 + */ +public class Reload4jLoggerFactory implements ILoggerFactory { + + private static final String LOG4J_DELEGATION_LOOP_URL = "http://www.slf4j.org/codes.html#log4jDelegationLoop"; + + // check for delegation loops + static { + try { + Class.forName("org.apache.log4j.Log4jLoggerFactory"); + String part1 = "Detected both log4j-over-slf4j.jar AND bound slf4j-reload4j.jar on the class path, preempting StackOverflowError. "; + String part2 = "See also " + LOG4J_DELEGATION_LOOP_URL + " for more details."; + + Util.report(part1); + Util.report(part2); + throw new IllegalStateException(part1 + part2); + } catch (ClassNotFoundException e) { + // this is the good case + } + } + + // key: name (String), value: a Log4jLoggerAdapter; + ConcurrentMap loggerMap; + + public Reload4jLoggerFactory() { + loggerMap = new ConcurrentHashMap(); + // force log4j to initialize + org.apache.log4j.LogManager.getRootLogger(); + } + + /* + * (non-Javadoc) + * + * @see org.slf4j.ILoggerFactory#getLogger(java.lang.String) + */ + public Logger getLogger(String name) { + Logger slf4jLogger = loggerMap.get(name); + if (slf4jLogger != null) { + return slf4jLogger; + } else { + org.apache.log4j.Logger log4jLogger; + if (name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME)) + log4jLogger = LogManager.getRootLogger(); + else + log4jLogger = LogManager.getLogger(name); + + Logger newInstance = new Reload4jLoggerAdapter(log4jLogger); + Logger oldInstance = loggerMap.putIfAbsent(name, newInstance); + return oldInstance == null ? newInstance : oldInstance; + } + } +} diff --git a/slf4j-reload4j/src/main/java/org/slf4j/impl/Reload4jMDCAdapter.java b/slf4j-reload4j/src/main/java/org/slf4j/impl/Reload4jMDCAdapter.java new file mode 100644 index 000000000..8420cabf1 --- /dev/null +++ b/slf4j-reload4j/src/main/java/org/slf4j/impl/Reload4jMDCAdapter.java @@ -0,0 +1,91 @@ +/** + * 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.impl; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.slf4j.spi.MDCAdapter; + +public class Reload4jMDCAdapter implements MDCAdapter { + + public void clear() { + @SuppressWarnings("rawtypes") + Map map = org.apache.log4j.MDC.getContext(); + if (map != null) { + map.clear(); + } + } + + public String get(String key) { + return (String) org.apache.log4j.MDC.get(key); + } + + /** + * Put a context value (the val parameter) as identified with + * the key parameter into the current thread's context map. The + * key parameter cannot be null. Log4j does not + * support null for the val parameter. + * + *

+ * This method delegates all work to log4j's MDC. + * + * @throws IllegalArgumentException + * in case the "key" or "val" parameter is null + */ + public void put(String key, String val) { + org.apache.log4j.MDC.put(key, val); + } + + public void remove(String key) { + org.apache.log4j.MDC.remove(key); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public Map getCopyOfContextMap() { + Map old = org.apache.log4j.MDC.getContext(); + if (old != null) { + return new HashMap(old); + } else { + return null; + } + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void setContextMap(Map contextMap) { + Map old = org.apache.log4j.MDC.getContext(); + if (old == null) { + Iterator entrySetIterator = contextMap.entrySet().iterator(); + while (entrySetIterator.hasNext()) { + Map.Entry mapEntry = (Map.Entry) entrySetIterator.next(); + org.apache.log4j.MDC.put((String) mapEntry.getKey(), mapEntry.getValue()); + } + } else { + old.clear(); + old.putAll(contextMap); + } + } +} diff --git a/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticLoggerBinder.java b/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticLoggerBinder.java new file mode 100644 index 000000000..2296cef36 --- /dev/null +++ b/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticLoggerBinder.java @@ -0,0 +1,88 @@ +/** + * 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.impl; + +import org.apache.log4j.Level; +import org.slf4j.ILoggerFactory; +import org.slf4j.LoggerFactory; +import org.slf4j.helpers.Util; +import org.slf4j.spi.LoggerFactoryBinder; + +/** + * The binding of {@link LoggerFactory} class with an actual instance of + * {@link ILoggerFactory} is performed using information returned by this class. + * + * @author Ceki Gülcü + */ +public class StaticLoggerBinder implements LoggerFactoryBinder { + + /** + * The unique instance of this class. + * + */ + private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); + + /** + * Return the singleton of this class. + * + * @return the StaticLoggerBinder singleton + */ + public static final StaticLoggerBinder getSingleton() { + return SINGLETON; + } + + /** + * Declare the version of the SLF4J API this implementation is compiled against. + * The value of this field is modified with each major release. + */ + // to avoid constant folding by the compiler, this field must *not* be final + public static String REQUESTED_API_VERSION = "1.6.99"; // !final + + private static final String loggerFactoryClassStr = Reload4jLoggerFactory.class.getName(); + + /** + * The ILoggerFactory instance returned by the {@link #getLoggerFactory} + * method should always be the same object + */ + private final ILoggerFactory loggerFactory; + + private StaticLoggerBinder() { + loggerFactory = new Reload4jLoggerFactory(); + try { + @SuppressWarnings("unused") + Level level = Level.TRACE; + } catch (NoSuchFieldError nsfe) { + Util.report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version"); + } + } + + public ILoggerFactory getLoggerFactory() { + return loggerFactory; + } + + public String getLoggerFactoryClassStr() { + return loggerFactoryClassStr; + } +} diff --git a/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticMDCBinder.java new file mode 100644 index 000000000..066c68b76 --- /dev/null +++ b/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -0,0 +1,65 @@ +/** + * 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.impl; + +import org.slf4j.spi.MDCAdapter; + +/** + * This implementation is bound to {@link Reload4jMDCAdapter}. + * + * @author Ceki Gülcü + */ +public class StaticMDCBinder { + + /** + * The unique instance of this class. + */ + public static final StaticMDCBinder SINGLETON = new StaticMDCBinder(); + + private StaticMDCBinder() { + } + + /** + * Return the singleton of this class. + * + * @return the StaticMDCBinder singleton + * @since 1.7.14 + */ + public static final StaticMDCBinder getSingleton() { + return SINGLETON; + } + + /** + * Currently this method always returns an instance of + * {@link StaticMDCBinder}. + */ + public MDCAdapter getMDCA() { + return new Reload4jMDCAdapter(); + } + + public String getMDCAdapterClassStr() { + return Reload4jMDCAdapter.class.getName(); + } +} diff --git a/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticMarkerBinder.java new file mode 100644 index 000000000..bd3404f0d --- /dev/null +++ b/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -0,0 +1,78 @@ +/** + * 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.impl; + +import org.slf4j.IMarkerFactory; +import org.slf4j.MarkerFactory; +import org.slf4j.helpers.BasicMarkerFactory; +import org.slf4j.spi.MarkerFactoryBinder; + +/** + * + * The binding of {@link MarkerFactory} class with an actual instance of + * {@link IMarkerFactory} is performed using information returned by this class. + * + * @author Ceki Gülcü + * @since 1.7.33 + */ +public class StaticMarkerBinder implements MarkerFactoryBinder { + + /** + * The unique instance of this class. + */ + public static final StaticMarkerBinder SINGLETON = new StaticMarkerBinder(); + + final IMarkerFactory markerFactory = new BasicMarkerFactory(); + + private StaticMarkerBinder() { + } + + /** + * Return the singleton of this class. + * + * @return the StaticMarkerBinder singleton + * @since 1.7.14 + */ + public static StaticMarkerBinder getSingleton() { + return SINGLETON; + } + + /** + * Currently this method always returns an instance of + * {@link BasicMarkerFactory}. + */ + public IMarkerFactory getMarkerFactory() { + return markerFactory; + } + + /** + * Currently, this method returns the class name of + * {@link BasicMarkerFactory}. + */ + public String getMarkerFactoryClassStr() { + return BasicMarkerFactory.class.getName(); + } + +} diff --git a/slf4j-reload4j/src/main/resources/META-INF/MANIFEST.MF b/slf4j-reload4j/src/main/resources/META-INF/MANIFEST.MF new file mode 100755 index 000000000..0575e6303 --- /dev/null +++ b/slf4j-reload4j/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Implementation-Title: slf4j-reload4j +Bundle-ManifestVersion: 2 +Bundle-SymbolicName: slf4j.reload4k +Bundle-Name: slf4j-reload4j +Bundle-Vendor: SLF4J.ORG +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Export-Package: org.slf4j.impl;version=${parsedVersion.osgiVersion} +Import-Package: org.slf4j;version=${parsedVersion.osgiVersion}, + org.slf4j.spi;version=${parsedVersion.osgiVersion}, + org.slf4j.helpers;version=${parsedVersion.osgiVersion}, + org.slf4j.event;version=${parsedVersion.osgiVersion}, + org.apache.log4j +Fragment-Host: slf4j.api diff --git a/slf4j-reload4j/src/test/java/org/slf4j/InvocationTest.java b/slf4j-reload4j/src/test/java/org/slf4j/InvocationTest.java new file mode 100644 index 000000000..f736f89fe --- /dev/null +++ b/slf4j-reload4j/src/test/java/org/slf4j/InvocationTest.java @@ -0,0 +1,185 @@ +/** + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.spi.LoggingEvent; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Test whether invoking the SLF4J API causes problems or not. + * + * @author Ceki Gulcu + * + */ +public class InvocationTest { + + ListAppender listAppender = new ListAppender(); + org.apache.log4j.Logger root; + + @Before + public void setUp() throws Exception { + root = org.apache.log4j.Logger.getRootLogger(); + root.addAppender(listAppender); + } + + @After + public void tearDown() throws Exception { + root.getLoggerRepository().resetConfiguration(); + } + + @Test + public void test1() { + Logger logger = LoggerFactory.getLogger("test1"); + logger.debug("Hello world."); + assertEquals(1, listAppender.list.size()); + } + + @Test + public void test2() { + Integer i1 = Integer.valueOf(1); + Integer i2 = Integer.valueOf(2); + Integer i3 = Integer.valueOf(3); + Exception e = new Exception("This is a test exception."); + Logger logger = LoggerFactory.getLogger("test2"); + + logger.trace("Hello trace."); + + logger.debug("Hello world 1."); + logger.debug("Hello world {}", i1); + logger.debug("val={} val={}", i1, i2); + logger.debug("val={} val={} val={}", new Object[] { i1, i2, i3 }); + + logger.debug("Hello world 2", e); + logger.info("Hello world 2."); + + logger.warn("Hello world 3."); + logger.warn("Hello world 3", e); + + logger.error("Hello world 4."); + logger.error("Hello world {}", Integer.valueOf(3)); + logger.error("Hello world 4.", e); + assertEquals(11, listAppender.list.size()); + } + + @Test + public void testNull() { + Logger logger = LoggerFactory.getLogger("testNull"); + logger.trace(null); + logger.debug(null); + logger.info(null); + logger.warn(null); + logger.error(null); + + Exception e = new Exception("This is a test exception."); + logger.debug(null, e); + logger.info(null, e); + logger.warn(null, e); + logger.error(null, e); + assertEquals(8, listAppender.list.size()); + } + + // http://jira.qos.ch/browse/SLF4J-69 + // formerly http://bugzilla.slf4j.org/show_bug.cgi?id=78 + @Test + public void testNullParameter_BUG78() { + Logger logger = LoggerFactory.getLogger("testNullParameter_BUG78"); + String[] parameters = null; + String msg = "hello {}"; + + logger.debug(msg, (Object[]) parameters); + + assertEquals(1, listAppender.list.size()); + LoggingEvent e = (LoggingEvent) listAppender.list.get(0); + assertEquals(msg, e.getMessage()); + } + + @Test + public void testMarker() { + Logger logger = LoggerFactory.getLogger("testMarker"); + Marker blue = MarkerFactory.getMarker("BLUE"); + logger.trace(blue, "hello"); + logger.debug(blue, "hello"); + logger.info(blue, "hello"); + logger.warn(blue, "hello"); + logger.error(blue, "hello"); + + logger.debug(blue, "hello {}", "world"); + logger.info(blue, "hello {}", "world"); + logger.warn(blue, "hello {}", "world"); + logger.error(blue, "hello {}", "world"); + + logger.debug(blue, "hello {} and {} ", "world", "universe"); + logger.info(blue, "hello {} and {} ", "world", "universe"); + logger.warn(blue, "hello {} and {} ", "world", "universe"); + logger.error(blue, "hello {} and {} ", "world", "universe"); + assertEquals(12, listAppender.list.size()); + } + + @Test + public void testMDC() { + MDC.put("k", "v"); + assertNotNull(MDC.get("k")); + assertEquals("v", MDC.get("k")); + + MDC.remove("k"); + assertNull(MDC.get("k")); + + MDC.put("k1", "v1"); + assertEquals("v1", MDC.get("k1")); + MDC.clear(); + assertNull(MDC.get("k1")); + + try { + MDC.put(null, "x"); + fail("null keys are invalid"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testMDCContextMapValues() { + Map map = new HashMap(); + map.put("ka", "va"); + map.put("kb", "vb"); + + MDC.put("k", "v"); + assertEquals("v", MDC.get("k")); + MDC.setContextMap(map); + assertNull(MDC.get("k")); + assertEquals("va", MDC.get("ka")); + assertEquals("vb", MDC.get("kb")); + } + +} diff --git a/slf4j-reload4j/src/test/java/org/slf4j/ListAppender.java b/slf4j-reload4j/src/test/java/org/slf4j/ListAppender.java new file mode 100644 index 000000000..295968993 --- /dev/null +++ b/slf4j-reload4j/src/test/java/org/slf4j/ListAppender.java @@ -0,0 +1,53 @@ +/** + * 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.util.ArrayList; +import java.util.List; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.spi.LoggingEvent; + +public class ListAppender extends AppenderSkeleton { + + public List list = new ArrayList(); + + public boolean extractLocationInfo = false; + + protected void append(LoggingEvent event) { + list.add(event); + if (extractLocationInfo) { + event.getLocationInformation(); + } + } + + public void close() { + } + + public boolean requiresLayout() { + return false; + } + +} diff --git a/slf4j-reload4j/src/test/java/org/slf4j/MDCTest.java b/slf4j-reload4j/src/test/java/org/slf4j/MDCTest.java new file mode 100755 index 000000000..d366797cd --- /dev/null +++ b/slf4j-reload4j/src/test/java/org/slf4j/MDCTest.java @@ -0,0 +1,28 @@ +package org.slf4j; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.Random; + +import org.apache.log4j.MDC; +import org.junit.Test; + +public class MDCTest { + + + private static Random random = new Random(); + int diff = random.nextInt(1024*8); + + @Test + public void smoke() { + String key = "MDCFriendTest.smoke"+diff; + String val = "val"+diff; + MDC.put(key, val); + assertEquals(val, MDC.get(key)); + MDC.clear(); + assertNull(MDC.get(key)); + + } + +} diff --git a/slf4j-reload4j/src/test/java/org/slf4j/impl/Log4j12MultithreadedInitializationTest.java b/slf4j-reload4j/src/test/java/org/slf4j/impl/Log4j12MultithreadedInitializationTest.java new file mode 100644 index 000000000..a651e8f04 --- /dev/null +++ b/slf4j-reload4j/src/test/java/org/slf4j/impl/Log4j12MultithreadedInitializationTest.java @@ -0,0 +1,73 @@ +/** + * 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.impl; + +import java.util.List; + +import org.apache.log4j.LogManager; +import org.apache.log4j.spi.LoggingEvent; +import org.junit.After; +import org.junit.Before; +import static org.junit.Assert.assertNotNull; + +import org.slf4j.helpers.MultithreadedInitializationTest; + +public class Log4j12MultithreadedInitializationTest extends MultithreadedInitializationTest { + static int NUM_LINES_BY_RECURSIVE_APPENDER = 3; + + // value of LogManager.DEFAULT_CONFIGURATION_KEY; + static String CONFIG_FILE_KEY = "log4j.configuration"; + final String loggerName = this.getClass().getName(); + + @Before + public void setup() { + System.setProperty(CONFIG_FILE_KEY, "recursiveInitWithActivationDelay.properties"); + System.out.println("THREAD_COUNT=" + THREAD_COUNT); + } + + @After + public void tearDown() throws Exception { + System.clearProperty(CONFIG_FILE_KEY); + } + + protected long getRecordedEventCount() { + List eventList = getRecordedEvents(); + assertNotNull(eventList); + return eventList.size(); + } + + protected int extraLogEvents() { + return NUM_LINES_BY_RECURSIVE_APPENDER; + } + + private List getRecordedEvents() { + org.apache.log4j.Logger root = LogManager.getRootLogger(); + + RecursiveAppender ra = (RecursiveAppender) root.getAppender("RECURSIVE"); + assertNotNull(ra); + return ra.events; + } + +} diff --git a/slf4j-reload4j/src/test/java/org/slf4j/impl/RecursiveAppender.java b/slf4j-reload4j/src/test/java/org/slf4j/impl/RecursiveAppender.java new file mode 100644 index 000000000..6c1e64143 --- /dev/null +++ b/slf4j-reload4j/src/test/java/org/slf4j/impl/RecursiveAppender.java @@ -0,0 +1,88 @@ +/** + * 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.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.spi.LoggingEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RecursiveAppender extends AppenderSkeleton { + + int diff = new Random().nextInt(); + int activationDelay = 0; + String loggerName = "org.slf4j.impl.RecursiveAppender" + diff; + + List events = new ArrayList(); + + public RecursiveAppender() { + System.out.println("entering RecursiveAppender constructor"); + Logger logger = LoggerFactory.getLogger(loggerName); + logger.info("Calling a logger in the constructor"); + System.out.println("exiting RecursiveAppender constructor"); + } + + protected void append(LoggingEvent e) { + events.add(e); + } + + public void close() { + } + + public boolean requiresLayout() { + return false; + } + + @Override + public void activateOptions() { + System.out.println("entering RecursiveAppender.activateOptions"); + if (activationDelay > 0) { + Logger logger = LoggerFactory.getLogger(loggerName); + logger.info("About to wait {} millis", activationDelay); + try { + Thread.sleep(activationDelay); + } catch (InterruptedException e) { + e.printStackTrace(); + } + logger.info("Done waiting {} millis", activationDelay); + } + super.activateOptions(); + + System.out.println("exiting RecursiveAppender.activateOptions"); + } + + public int getActivationDelay() { + return activationDelay; + } + + public void setActivationDelay(int activationDelay) { + this.activationDelay = activationDelay; + } + +} diff --git a/slf4j-reload4j/src/test/java/org/slf4j/impl/RecursiveInitializationTest.java b/slf4j-reload4j/src/test/java/org/slf4j/impl/RecursiveInitializationTest.java new file mode 100755 index 000000000..f6d485efd --- /dev/null +++ b/slf4j-reload4j/src/test/java/org/slf4j/impl/RecursiveInitializationTest.java @@ -0,0 +1,54 @@ +/** + * 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.impl; + +import java.util.Random; + +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RecursiveInitializationTest { + + // value of LogManager.DEFAULT_CONFIGURATION_KEY; + static String CONFIG_FILE_KEY = "log4j.configuration"; + + int diff = new Random().nextInt(10000); + String loggerName = "org.slf4j.impl.RecursiveInitializationTest"; + + @After + public void tearDown() throws Exception { + System.clearProperty(CONFIG_FILE_KEY); + } + + @Test + public void loggingDuringInitialization() { + System.setProperty(CONFIG_FILE_KEY, "recursiveInit.properties"); + Logger logger = LoggerFactory.getLogger(loggerName + ".loggingDuringInitialization-" + diff); + logger.info("hello"); + } + +} diff --git a/slf4j-reload4j/src/test/resources/recursiveInit.properties b/slf4j-reload4j/src/test/resources/recursiveInit.properties new file mode 100644 index 000000000..a8d5d7653 --- /dev/null +++ b/slf4j-reload4j/src/test/resources/recursiveInit.properties @@ -0,0 +1,8 @@ +log4j.debug=true +log4j.rootLogger=DEBUG, RECURSIVE + +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=%d [%t] %c - %m%n + +log4j.appender.RECURSIVE=org.slf4j.impl.RecursiveAppender \ No newline at end of file diff --git a/slf4j-reload4j/src/test/resources/recursiveInitWithActivationDelay.properties b/slf4j-reload4j/src/test/resources/recursiveInitWithActivationDelay.properties new file mode 100755 index 000000000..47685626e --- /dev/null +++ b/slf4j-reload4j/src/test/resources/recursiveInitWithActivationDelay.properties @@ -0,0 +1,9 @@ +log4j.debug=true +log4j.rootLogger=DEBUG, CONSOLE, RECURSIVE + +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=CON %d [%t] %c - %m%n + +log4j.appender.RECURSIVE=org.slf4j.impl.RecursiveAppender +log4j.appender.RECURSIVE.activationDelay=10 \ No newline at end of file diff --git a/slf4j-simple/LICENSE.txt b/slf4j-simple/LICENSE.txt index 508a27283..bdfc03e45 100644 --- a/slf4j-simple/LICENSE.txt +++ b/slf4j-simple/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2004-2007 QOS.ch +Copyright (c) 2004-2022 QOS.ch All rights reserved. Permission is hereby granted, free of charge, to any person obtaining