diff --git a/integration/pom.xml b/integration/pom.xml index 7ce6fc0..c8a3319 100644 --- a/integration/pom.xml +++ b/integration/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 integration diff --git a/jcl-over-slf4j/pom.xml b/jcl-over-slf4j/pom.xml index 8064060..ec0c4f3 100644 --- a/jcl-over-slf4j/pom.xml +++ b/jcl-over-slf4j/pom.xml @@ -5,7 +5,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 4.0.0 diff --git a/jul-to-slf4j/pom.xml b/jul-to-slf4j/pom.xml index 90593bc..b4d604d 100644 --- a/jul-to-slf4j/pom.xml +++ b/jul-to-slf4j/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 jul-to-slf4j diff --git a/log4j-over-slf4j/pom.xml b/log4j-over-slf4j/pom.xml index 03a3c34..4a26117 100644 --- a/log4j-over-slf4j/pom.xml +++ b/log4j-over-slf4j/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 diff --git a/osgi-over-slf4j/pom.xml b/osgi-over-slf4j/pom.xml index fa7a5ac..998ddd4 100644 --- a/osgi-over-slf4j/pom.xml +++ b/osgi-over-slf4j/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 osgi-over-slf4j diff --git a/pom.xml b/pom.xml index 4e4f51e..43ae5ee 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 pom SLF4J diff --git a/slf4j-android/pom.xml b/slf4j-android/pom.xml index 8b0303d..05a6480 100644 --- a/slf4j-android/pom.xml +++ b/slf4j-android/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 slf4j-android diff --git a/slf4j-api/pom.xml b/slf4j-api/pom.xml index a7fcea9..dc9466c 100644 --- a/slf4j-api/pom.xml +++ b/slf4j-api/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 slf4j-api diff --git a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java index ce76f1e..2601678 100644 --- a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java @@ -54,12 +54,12 @@ *

*

* Please note that all methods in LoggerFactory are static. - * - * + * + * * @author Alexander Dorokhine * @author Robert Elliot * @author Ceki Gülcü - * + * */ public final class LoggerFactory { @@ -140,7 +140,8 @@ private final static void bind() { try { Set staticLoggerBinderPathSet = null; - // skip check under android, see also http://jira.qos.ch/browse/SLF4J-328 + // skip check under android, see also + // http://jira.qos.ch/browse/SLF4J-328 if (!isAndroid()) { staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet(); reportMultipleBindingAmbiguity(staticLoggerBinderPathSet); @@ -149,7 +150,10 @@ StaticLoggerBinder.getSingleton(); INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION; reportActualBinding(staticLoggerBinderPathSet); + fixSubstituteLoggers(); replayEvents(); + // release all resources in SUBST_FACTORY + SUBST_FACTORY.clear(); } catch (NoClassDefFoundError ncde) { String msg = ncde.getMessage(); if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) { @@ -174,6 +178,17 @@ failedBinding(e); throw new IllegalStateException("Unexpected initialization failure", e); } + } + + 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) { @@ -217,8 +232,7 @@ SubstituteLogger substLogger = event.getLogger(); String loggerName = substLogger.getName(); if (substLogger.isDelegateNull()) { - Logger logger = getLogger(loggerName); - substLogger.setDelegate(logger); + throw new IllegalStateException("Delegate logger cannot be null at this state."); } if (substLogger.isDelegateNOP()) { @@ -270,13 +284,15 @@ } } - // We need to use the name of the StaticLoggerBinder class, but we can't reference + // 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 + // LinkedHashSet appropriate here because it preserves insertion order + // during iteration Set staticLoggerBinderPathSet = new LinkedHashSet(); try { ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader(); @@ -301,9 +317,9 @@ } /** - * 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 binderPathSet) { if (isAmbiguousStaticLoggerBinderPathSet(binderPathSet)) { @@ -330,10 +346,11 @@ } /** - * Return a logger named according to the name parameter using the statically - * bound {@link ILoggerFactory} instance. - * - * @param name The name of the logger. + * 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) { @@ -342,20 +359,25 @@ } /** - * 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 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 + * + * + * @see Detected + * logger name mismatch */ public static Logger getLogger(Class clazz) { Logger logger = getLogger(clazz.getName()); @@ -379,7 +401,7 @@ *

*

* ILoggerFactory instance is bound with this class at compile time. - * + * * @return the ILoggerFactory instance in use */ public static ILoggerFactory getILoggerFactory() { diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLogger.java b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLogger.java index 2de429b..ec0d768 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLogger.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLogger.java @@ -53,9 +53,12 @@ private EventRecodingLogger eventRecodingLogger; private Queue eventQueue; - public SubstituteLogger(String name, Queue eventQueue) { + private final boolean createdPostInitialization; + + public SubstituteLogger(String name, Queue eventQueue, boolean createdPostInitialization) { this.name = name; this.eventQueue = eventQueue; + this.createdPostInitialization = createdPostInitialization; } public String getName() { @@ -327,7 +330,14 @@ * instance. */ Logger delegate() { - return _delegate != null ? _delegate : getEventRecordingLogger(); + if(_delegate != null) { + return _delegate; + } + if(createdPostInitialization) { + return NOPLogger.NOP_LOGGER; + } else { + return getEventRecordingLogger(); + } } private Logger getEventRecordingLogger() { diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java index 37f7491..c5a6b0e 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java @@ -25,9 +25,9 @@ package org.slf4j.helpers; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; +import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; import org.slf4j.ILoggerFactory; @@ -42,17 +42,17 @@ */ public class SubstituteLoggerFactory implements ILoggerFactory { - final ConcurrentMap loggers = new ConcurrentHashMap(); + boolean postInitialization = false; + + final Map loggers = new HashMap(); final LinkedBlockingQueue eventQueue = new LinkedBlockingQueue(); - public Logger getLogger(String name) { + synchronized public Logger getLogger(String name) { SubstituteLogger logger = loggers.get(name); if (logger == null) { - logger = new SubstituteLogger(name, eventQueue); - SubstituteLogger oldLogger = loggers.putIfAbsent(name, logger); - if (oldLogger != null) - logger = oldLogger; + logger = new SubstituteLogger(name, eventQueue, postInitialization); + loggers.put(name, logger); } return logger; } @@ -69,6 +69,10 @@ return eventQueue; } + public void postInitialization() { + postInitialization = true; + } + public void clear() { loggers.clear(); eventQueue.clear(); diff --git a/slf4j-api/src/test/java/org/slf4j/FindStaticLoggerBinderPathsPerfTest.hava b/slf4j-api/src/test/java/org/slf4j/FindStaticLoggerBinderPathsPerfTest.hava deleted file mode 100644 index 9c3fdd2..0000000 --- a/slf4j-api/src/test/java/org/slf4j/FindStaticLoggerBinderPathsPerfTest.hava +++ /dev/null @@ -1,55 +0,0 @@ -package org.slf4j; - -import org.junit.Ignore; -import org.junit.Test; - -public class FindStaticLoggerBinderPathsPerfTest { - - @Test - @Ignore - public void test() { - long duration = timeFindBindingSetCall(); - System.out.println(duration / (1000) + " microseconds"); - - int count = 10; - long sum = 0; - for (int i = 0; i < count; i++) { - sum += timeFindBindingSetCall(); - } - System.out.println(sum / (count * 1000) + " microseconds in average"); - } - - @Test - public void testAsync() throws InterruptedException { - long start = System.nanoTime(); - FindPathSetThread thread = new FindPathSetThread(); - thread.start(); - long end = System.nanoTime(); - - long duration = end - start; - System.out.println(duration / (1000) + " microseconds"); - - thread.join(); - } - - long timeFindBindingSetCall() { - long start = System.nanoTime(); - - LoggerFactory.findPossibleStaticLoggerBinderPathSet(); - long end = System.nanoTime(); - return end - start; - - } - - static class FindPathSetThread extends Thread { - - public void run() { - long start = System.nanoTime(); - LoggerFactory.findPossibleStaticLoggerBinderPathSet(); - long end = System.nanoTime(); - - System.out.println("Found set in " + (end - start)/1000 + " microseconds"); - - } - } -} diff --git a/slf4j-api/src/test/java/org/slf4j/LoggerAccessingThread.java b/slf4j-api/src/test/java/org/slf4j/LoggerAccessingThread.java index 383e7e5..ec611d0 100644 --- a/slf4j-api/src/test/java/org/slf4j/LoggerAccessingThread.java +++ b/slf4j-api/src/test/java/org/slf4j/LoggerAccessingThread.java @@ -24,6 +24,7 @@ */ package org.slf4j; +import java.util.List; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.atomic.AtomicLong; @@ -33,9 +34,11 @@ final CyclicBarrier barrier; final int count; final AtomicLong eventCount; - - public LoggerAccessingThread(final CyclicBarrier barrier, final int count, final AtomicLong eventCount) { + List loggerList; + + public LoggerAccessingThread(final CyclicBarrier barrier, List loggerList, final int count, final AtomicLong eventCount) { this.barrier = barrier; + this.loggerList = loggerList; this.count = count; this.eventCount = eventCount; } @@ -50,6 +53,8 @@ String loggerNamePrefix = this.getClass().getName(); for (int i = 0; i < LOOP_LEN; i++) { Logger logger = LoggerFactory.getLogger(loggerNamePrefix + "-" + count + "-" + i); + loggerList.add(logger); + Thread.yield(); logger.info("in run method"); eventCount.getAndIncrement(); } diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/MultithreadedInitializationTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/MultithreadedInitializationTest.java new file mode 100644 index 0000000..435d2bd --- /dev/null +++ b/slf4j-api/src/test/java/org/slf4j/helpers/MultithreadedInitializationTest.java @@ -0,0 +1,81 @@ +package org.slf4j.helpers; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.atomic.AtomicLong; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerAccessingThread; +import org.slf4j.LoggerFactory; +import org.slf4j.event.EventRecodingLogger; + +abstract public class MultithreadedInitializationTest { + final protected static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2; + + private final List createdLoggers = Collections.synchronizedList(new ArrayList()); + + final private AtomicLong eventCount = new AtomicLong(0); + final private CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); + + int diff = new Random().nextInt(10000); + + @Test + public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException { + @SuppressWarnings("unused") + LoggerAccessingThread[] accessors = harness(); + + Logger logger = LoggerFactory.getLogger(getClass().getName()); + logger.info("hello"); + eventCount.getAndIncrement(); + + assertAllSubstLoggersAreFixed(); + long recordedEventCount = getRecordedEventCount(); + int LENIENCY_COUNT = 16; + + long expectedEventCount = eventCount.get() + extraLogEvents(); + + assertTrue(expectedEventCount + " >= " + recordedEventCount, expectedEventCount >= recordedEventCount); + assertTrue(expectedEventCount + " < " + recordedEventCount + "+" + LENIENCY_COUNT, expectedEventCount < recordedEventCount + LENIENCY_COUNT); + } + + abstract protected long getRecordedEventCount(); + + protected int extraLogEvents() { + return 0; + } + + private void assertAllSubstLoggersAreFixed() { + for (Logger logger : createdLoggers) { + if (logger instanceof SubstituteLogger) { + SubstituteLogger substLogger = (SubstituteLogger) logger; + if (substLogger.delegate() instanceof EventRecodingLogger) + fail("substLogger " + substLogger.getName() + " has a delegate of type EventRecodingLogger"); + } + } + } + + private LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException { + LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT]; + for (int i = 0; i < THREAD_COUNT; i++) { + threads[i] = new LoggerAccessingThread(barrier, createdLoggers, i, eventCount); + threads[i].start(); + } + + // trigger barrier + barrier.await(); + + for (int i = 0; i < THREAD_COUNT; i++) { + threads[i].join(); + } + + return threads; + } +} diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java index 0df5336..dc7672e 100644 --- a/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java +++ b/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java @@ -40,6 +40,7 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.event.EventRecodingLogger; +import org.slf4j.helpers.SubstituteLogger; /** * @author Chetan Mehrotra @@ -49,7 +50,7 @@ @Test public void testDelegate() throws Exception { - SubstituteLogger log = new SubstituteLogger("foo", null); + SubstituteLogger log = new SubstituteLogger("foo", null, false); assertTrue(log.delegate() instanceof EventRecodingLogger); Set expectedMethodSignatures = determineMethodSignatures(Logger.class); diff --git a/slf4j-ext/pom.xml b/slf4j-ext/pom.xml index 946f662..89425e1 100644 --- a/slf4j-ext/pom.xml +++ b/slf4j-ext/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 slf4j-ext diff --git a/slf4j-jcl/pom.xml b/slf4j-jcl/pom.xml index 7385e08..b450da1 100644 --- a/slf4j-jcl/pom.xml +++ b/slf4j-jcl/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 slf4j-jcl diff --git a/slf4j-jdk14/pom.xml b/slf4j-jdk14/pom.xml index ad34db0..e6263ee 100644 --- a/slf4j-jdk14/pom.xml +++ b/slf4j-jdk14/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 slf4j-jdk14 diff --git a/slf4j-jdk14/src/test/java/org/slf4j/helpers/CountingHandler.java b/slf4j-jdk14/src/test/java/org/slf4j/helpers/CountingHandler.java new file mode 100644 index 0000000..33c36b9 --- /dev/null +++ b/slf4j-jdk14/src/test/java/org/slf4j/helpers/CountingHandler.java @@ -0,0 +1,24 @@ +package org.slf4j.helpers; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Handler; +import java.util.logging.LogRecord; + +public class CountingHandler extends Handler { + + final AtomicLong eventCount = new AtomicLong(0); + + @Override + public void publish(LogRecord record) { + eventCount.getAndIncrement(); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + +} diff --git a/slf4j-jdk14/src/test/java/org/slf4j/helpers/JDK14MultithreadedInitializationTest.java b/slf4j-jdk14/src/test/java/org/slf4j/helpers/JDK14MultithreadedInitializationTest.java new file mode 100644 index 0000000..cbcbcf5 --- /dev/null +++ b/slf4j-jdk14/src/test/java/org/slf4j/helpers/JDK14MultithreadedInitializationTest.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2004-2016 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.helpers; + +import static org.junit.Assert.fail; + +import java.util.logging.Handler; + +import org.junit.After; +import org.junit.Before; + +public class JDK14MultithreadedInitializationTest extends MultithreadedInitializationTest { + + java.util.logging.Logger julRootLogger = java.util.logging.Logger.getLogger(""); + java.util.logging.Logger julOrgLogger = java.util.logging.Logger.getLogger("org"); + + @Before + public void addRecordingHandler() { + System.out.println("THREAD_COUNT=" + THREAD_COUNT); + removeAllHandlers(julRootLogger); + removeAllHandlers(julOrgLogger); + julOrgLogger.addHandler(new CountingHandler()); + } + + private void removeAllHandlers(java.util.logging.Logger logger) { + Handler[] handlers = logger.getHandlers(); + for (int i = 0; i < handlers.length; i++) { + logger.removeHandler(handlers[i]); + } + } + + @After + public void tearDown() throws Exception { + removeAllHandlers(julOrgLogger); + } + + protected long getRecordedEventCount() { + CountingHandler ra = findRecordingHandler(); + if (ra == null) { + fail("failed to fing RecordingHandler"); + } + return ra.eventCount.get(); + } + + private CountingHandler findRecordingHandler() { + Handler[] handlers = julOrgLogger.getHandlers(); + for (Handler h : handlers) { + if (h instanceof CountingHandler) + return (CountingHandler) h; + } + return null; + } + +} diff --git a/slf4j-jdk14/src/test/java/org/slf4j/impl/CountingHandler.java b/slf4j-jdk14/src/test/java/org/slf4j/impl/CountingHandler.java deleted file mode 100644 index 1d56090..0000000 --- a/slf4j-jdk14/src/test/java/org/slf4j/impl/CountingHandler.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.slf4j.impl; - -import java.util.concurrent.atomic.AtomicLong; -import java.util.logging.Handler; -import java.util.logging.LogRecord; - -public class CountingHandler extends Handler { - - final AtomicLong eventCount = new AtomicLong(0); - - @Override - public void publish(LogRecord record) { - eventCount.getAndIncrement(); - } - - @Override - public void flush() { - } - - @Override - public void close() throws SecurityException { - } - -} diff --git a/slf4j-jdk14/src/test/java/org/slf4j/impl/JDK14MultithreadedInitializationTest.java b/slf4j-jdk14/src/test/java/org/slf4j/impl/JDK14MultithreadedInitializationTest.java deleted file mode 100644 index dfad51f..0000000 --- a/slf4j-jdk14/src/test/java/org/slf4j/impl/JDK14MultithreadedInitializationTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Copyright (c) 2004-2016 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.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Random; -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.atomic.AtomicLong; -import java.util.logging.Handler; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerAccessingThread; -import org.slf4j.LoggerFactory; - -public class JDK14MultithreadedInitializationTest { - - final static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2; - - final private AtomicLong eventCount = new AtomicLong(0); - final private CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); - - int diff = new Random().nextInt(10000); - - java.util.logging.Logger julRootLogger = java.util.logging.Logger.getLogger(""); - java.util.logging.Logger julOrgLogger = java.util.logging.Logger.getLogger("org"); - - @Before - public void addRecordingHandler() { - System.out.println("THREAD_COUNT=" + THREAD_COUNT); - removeAllHandlers(julRootLogger); - removeAllHandlers(julOrgLogger); - julOrgLogger.addHandler(new CountingHandler()); - } - - private void removeAllHandlers(java.util.logging.Logger logger) { - Handler[] handlers = logger.getHandlers(); - for (int i = 0; i < handlers.length; i++) { - logger.removeHandler(handlers[i]); - } - } - - @After - public void tearDown() throws Exception { - removeAllHandlers(julOrgLogger); - } - - @Test - public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException { - @SuppressWarnings("unused") - LoggerAccessingThread[] accessors = harness(); - - Logger logger = LoggerFactory.getLogger(getClass().getName()); - logger.info("hello"); - eventCount.getAndIncrement(); - - long recordedEventCount = getRecordedEventCount(); - assertTrue(eventCount.get() + " >= " + recordedEventCount, eventCount.get() >= recordedEventCount); - assertTrue(eventCount.get() + " < " + recordedEventCount + "+10", eventCount.get() < recordedEventCount + 10); - } - - private long getRecordedEventCount() { - CountingHandler ra = findRecordingHandler(); - if (ra == null) { - fail("failed to fing RecordingHandler"); - } - return ra.eventCount.get(); - } - - private CountingHandler findRecordingHandler() { - Handler[] handlers = julOrgLogger.getHandlers(); - for (Handler h : handlers) { - if (h instanceof CountingHandler) - return (CountingHandler) h; - } - return null; - } - - private LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException { - LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT]; - for (int i = 0; i < THREAD_COUNT; i++) { - threads[i] = new LoggerAccessingThread(barrier, i, eventCount); - threads[i].start(); - } - - // trigger barrier - barrier.await(); - - for (int i = 0; i < THREAD_COUNT; i++) { - threads[i].join(); - } - - return threads; - } - -} diff --git a/slf4j-log4j12/pom.xml b/slf4j-log4j12/pom.xml index 48c2150..4974dfd 100644 --- a/slf4j-log4j12/pom.xml +++ b/slf4j-log4j12/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 slf4j-log4j12 diff --git a/slf4j-log4j12/src/test/java/org/slf4j/impl/Log4j12MultithreadedInitializationTest.java b/slf4j-log4j12/src/test/java/org/slf4j/impl/Log4j12MultithreadedInitializationTest.java index b81b66f..725b12b 100644 --- a/slf4j-log4j12/src/test/java/org/slf4j/impl/Log4j12MultithreadedInitializationTest.java +++ b/slf4j-log4j12/src/test/java/org/slf4j/impl/Log4j12MultithreadedInitializationTest.java @@ -24,40 +24,27 @@ */ package org.slf4j.impl; -import static org.junit.Assert.assertEquals; - import java.util.List; -import java.util.Random; -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.atomic.AtomicLong; import org.apache.log4j.LogManager; import org.apache.log4j.spi.LoggingEvent; import org.junit.After; import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerAccessingThread; -import org.slf4j.LoggerFactory; +import static org.junit.Assert.assertNotNull; -public class Log4j12MultithreadedInitializationTest { +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 static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2; - - private final AtomicLong eventCount = new AtomicLong(0); - - private final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); - - final int diff = new Random().nextInt(10000); final String loggerName = this.getClass().getName(); @Before public void setup() { - System.out.println("THREAD_COUNT=" + THREAD_COUNT); + System.setProperty(CONFIG_FILE_KEY, "recursiveInitWithActivationDelay.properties"); + System.out.println("THREAD_COUNT=" + THREAD_COUNT); } @After @@ -65,42 +52,22 @@ System.clearProperty(CONFIG_FILE_KEY); } - @Test - public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException { - - System.setProperty(CONFIG_FILE_KEY, "recursiveInitWithActivationDelay.properties"); - - @SuppressWarnings("unused") - LoggerAccessingThread[] accessors = harness(); - - Logger logger = LoggerFactory.getLogger(loggerName + ".slowInitialization-" + diff); - logger.info("hello"); - eventCount.getAndIncrement(); - - List events = getRecordedEvents(); - int NUM_LINES_BY_RECURSIVE_APPENDER = 3; - assertEquals(eventCount.get() + NUM_LINES_BY_RECURSIVE_APPENDER, events.size()); + 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; } - private LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException { - LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT]; - for (int i = 0; i < THREAD_COUNT; i++) { - threads[i] = new LoggerAccessingThread(barrier, i, eventCount); - threads[i].start(); - } - - barrier.await(); - for (int i = 0; i < THREAD_COUNT; i++) { - threads[i].join(); - } - return threads; - } - } diff --git a/slf4j-migrator/pom.xml b/slf4j-migrator/pom.xml index 9375772..abfe930 100644 --- a/slf4j-migrator/pom.xml +++ b/slf4j-migrator/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 slf4j-migrator diff --git a/slf4j-nop/pom.xml b/slf4j-nop/pom.xml index a1fff90..966fc97 100644 --- a/slf4j-nop/pom.xml +++ b/slf4j-nop/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 slf4j-nop diff --git a/slf4j-simple/pom.xml b/slf4j-simple/pom.xml index 15b309f..3e28b51 100644 --- a/slf4j-simple/pom.xml +++ b/slf4j-simple/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 slf4j-simple diff --git a/slf4j-simple/src/test/java/org/slf4j/helpers/SimpleLoggerMultithreadedInitializationTest.java b/slf4j-simple/src/test/java/org/slf4j/helpers/SimpleLoggerMultithreadedInitializationTest.java new file mode 100644 index 0000000..967da70 --- /dev/null +++ b/slf4j-simple/src/test/java/org/slf4j/helpers/SimpleLoggerMultithreadedInitializationTest.java @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2004-2016 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.helpers; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.slf4j.LoggerFactoryFriend; +import org.slf4j.impl.SimpleLogger; + +public class SimpleLoggerMultithreadedInitializationTest extends MultithreadedInitializationTest { + // final static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2; + // private final List createdLoggers = Collections.synchronizedList(new ArrayList()); + // private final AtomicLong eventCount = new AtomicLong(0); + // + // private final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); + // + // final int diff = new Random().nextInt(10000); + static int NUM_LINES_IN_SLF4J_REPLAY_WARNING = 3; + private final PrintStream oldErr = System.err; + final String loggerName = this.getClass().getName(); + StringPrintStream sps = new StringPrintStream(oldErr, true); + + @Before + public void setup() { + System.out.println("THREAD_COUNT=" + THREAD_COUNT); + System.setErr(sps); + System.setProperty(SimpleLogger.LOG_FILE_KEY, "System.err"); + LoggerFactoryFriend.reset(); + } + + @After + public void tearDown() throws Exception { + LoggerFactoryFriend.reset(); + System.clearProperty(SimpleLogger.LOG_FILE_KEY); + System.setErr(oldErr); + } + + @Override + protected long getRecordedEventCount() { + return sps.stringList.size(); + }; + + @Override + protected int extraLogEvents() { + return NUM_LINES_IN_SLF4J_REPLAY_WARNING; + } + + static class StringPrintStream extends PrintStream { + + public static final String LINE_SEP = System.getProperty("line.separator"); + PrintStream other; + boolean duplicate = false; + + List stringList = Collections.synchronizedList(new ArrayList()); + + public StringPrintStream(PrintStream ps, boolean duplicate) { + super(ps); + other = ps; + this.duplicate = duplicate; + } + + public StringPrintStream(PrintStream ps) { + this(ps, false); + } + + public void print(String s) { + if (duplicate) + other.print(s); + stringList.add(s); + } + + public void println(String s) { + if (duplicate) + other.println(s); + stringList.add(s); + } + + public void println(Object o) { + if (duplicate) + other.println(o); + stringList.add(o.toString()); + } + } + +} diff --git a/slf4j-simple/src/test/java/org/slf4j/impl/SimpleLoggerMultithreadedInitializationTest.java b/slf4j-simple/src/test/java/org/slf4j/impl/SimpleLoggerMultithreadedInitializationTest.java deleted file mode 100644 index 17aa97d..0000000 --- a/slf4j-simple/src/test/java/org/slf4j/impl/SimpleLoggerMultithreadedInitializationTest.java +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Copyright (c) 2004-2016 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.junit.Assert.assertTrue; - -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.atomic.AtomicLong; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerAccessingThread; -import org.slf4j.LoggerFactory; -import org.slf4j.LoggerFactoryFriend; - -public class SimpleLoggerMultithreadedInitializationTest { - - final static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2; - - private final AtomicLong eventCount = new AtomicLong(0); - private final PrintStream oldErr = System.err; - private final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); - - final int diff = new Random().nextInt(10000); - final String loggerName = this.getClass().getName(); - StringPrintStream sps = new StringPrintStream(oldErr, true); - - @Before - public void setup() { - System.out.println("THREAD_COUNT=" + THREAD_COUNT); - System.setErr(sps); - System.setProperty(SimpleLogger.LOG_FILE_KEY, "System.err"); - LoggerFactoryFriend.reset(); - } - - @After - public void tearDown() throws Exception { - LoggerFactoryFriend.reset(); - System.clearProperty(SimpleLogger.LOG_FILE_KEY); - System.setErr(oldErr); - } - - @Test - public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException { - - @SuppressWarnings("unused") - LoggerAccessingThread[] accessors = harness(); - - Logger logger = LoggerFactory.getLogger(loggerName + diff); - logger.info("hello"); - eventCount.getAndIncrement(); - - int NUM_LINES_IN_SLF4J_REPLAY_WARNING = 3; - - long expected = eventCount.get() + NUM_LINES_IN_SLF4J_REPLAY_WARNING; - int actual = sps.stringList.size(); - assertTrue(expected + " >= " + actual, expected >= actual); - assertTrue(expected + " < " + actual + " + 16", expected < actual + 16); - } - - private LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException { - final LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT]; - for (int i = 0; i < THREAD_COUNT; i++) { - LoggerAccessingThread simpleLoggerThread = new LoggerAccessingThread(barrier, i, eventCount); - threads[i] = simpleLoggerThread; - simpleLoggerThread.start(); - } - - barrier.await(); - for (int i = 0; i < THREAD_COUNT; i++) { - threads[i].join(); - } - return threads; - } - - - static class StringPrintStream extends PrintStream { - - public static final String LINE_SEP = System.getProperty("line.separator"); - PrintStream other; - boolean duplicate = false; - - List stringList = Collections.synchronizedList(new ArrayList()); - - public StringPrintStream(PrintStream ps, boolean duplicate) { - super(ps); - other = ps; - this.duplicate = duplicate; - } - - public StringPrintStream(PrintStream ps) { - this(ps, false); - } - - public void print(String s) { - if (duplicate) - other.print(s); - stringList.add(s); - } - - public void println(String s) { - if (duplicate) - other.println(s); - stringList.add(s); - } - - public void println(Object o) { - if (duplicate) - other.println(o); - stringList.add(o.toString()); - } - }; - -} diff --git a/slf4j-site/pom.xml b/slf4j-site/pom.xml index 467645c..d681e09 100644 --- a/slf4j-site/pom.xml +++ b/slf4j-site/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.20 + 1.7.21 slf4j-site