diff --git a/log4j-over-slf4j/src/main/java/org/apache/log4j/Log4jLoggerFactory.java b/log4j-over-slf4j/src/main/java/org/apache/log4j/Log4jLoggerFactory.java index 738b6a6c..30b35221 100644 --- a/log4j-over-slf4j/src/main/java/org/apache/log4j/Log4jLoggerFactory.java +++ b/log4j-over-slf4j/src/main/java/org/apache/log4j/Log4jLoggerFactory.java @@ -17,7 +17,6 @@ package org.apache.log4j; import org.apache.log4j.spi.LoggerFactory; -import org.slf4j.helpers.Util; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -36,23 +35,6 @@ class Log4jLoggerFactory { // String, Logger private static ConcurrentMap log4jLoggers = new ConcurrentHashMap(); - private static final String LOG4J_DELEGATION_LOOP_URL = "http://www.slf4j.org/codes.html#log4jDelegationLoop"; - - // check for delegation loops - static { - try { - Class.forName("org.slf4j.impl.Log4jLoggerFactory"); - String part1 = "Detected both log4j-over-slf4j.jar AND slf4j-log4j12.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 - } - } - public static Logger getLogger(String name) { org.apache.log4j.Logger instance = log4jLoggers.get(name); if (instance != null) { diff --git a/osgi-over-slf4j/src/main/resources/META-INF/MANIFEST.MF b/osgi-over-slf4j/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 00000000..73cebcfc --- /dev/null +++ b/osgi-over-slf4j/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,8 @@ +Implementation-Title: osgi-over-slf4j +Bundle-ManifestVersion: 2 +Bundle-SymbolicName: org.slf4j.osgi-over-slf4j +Bundle-Name: OSGi LogService implemented over SLF4J +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-Activator: org.slf4j.osgi.logservice.impl.Activator +Bundle-Category: osgi +Import-Package: org.osgi.framework;version="[1.5,2)",org.osgi.service.log;version="[1.3,2)",org.slf4j;version=${parsedVersion.osgiVersion} diff --git a/slf4j-android/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-android/src/main/java/org/slf4j/impl/StaticMDCBinder.java index a484c525..aa61bfa5 100644 --- a/slf4j-android/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-android/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -44,6 +44,15 @@ public class 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 NOPMDCAdapter}. diff --git a/slf4j-android/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-android/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 52b05bac..a25d3976 100644 --- a/slf4j-android/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-android/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -49,6 +49,16 @@ public class StaticMarkerBinder implements MarkerFactoryBinder { 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}. diff --git a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java index 65b9de08..0af5ce44 100755 --- a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java @@ -84,6 +84,8 @@ public final class LoggerFactory { // Support for detecting mismatched logger names. static final String DETECT_LOGGER_NAME_MISMATCH_PROPERTY = "slf4j.detectLoggerNameMismatch"; + static final String JAVA_VENDOR_PROPERTY = "java.vendor.url"; + static boolean DETECT_LOGGER_NAME_MISMATCH = Util.safeGetBooleanSystemProperty(DETECT_LOGGER_NAME_MISMATCH_PROPERTY); /** @@ -254,6 +256,11 @@ public final class LoggerFactory { * */ private static void reportMultipleBindingAmbiguity(Set staticLoggerBinderPathSet) { + if(isAndroid()) { + // skip check under android, see also http://jira.qos.ch/browse/SLF4J-328 + return; + } + if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) { Util.report("Class path contains multiple SLF4J bindings."); for (URL path : staticLoggerBinderPathSet) { @@ -263,6 +270,13 @@ public final class LoggerFactory { } } + private static boolean isAndroid() { + String vendor = Util.safeGetSystemProperty(JAVA_VENDOR_PROPERTY); + if(vendor == null) + return false; + return vendor.toLowerCase().contains("android"); + } + private static void reportActualBinding(Set staticLoggerBinderPathSet) { if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) { Util.report("Actual binding is of type [" + StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr() + "]"); diff --git a/slf4j-api/src/main/java/org/slf4j/MDC.java b/slf4j-api/src/main/java/org/slf4j/MDC.java index 117774cf..08e6d0a9 100644 --- a/slf4j-api/src/main/java/org/slf4j/MDC.java +++ b/slf4j-api/src/main/java/org/slf4j/MDC.java @@ -85,9 +85,27 @@ public class MDC { private MDC() { } + /** + * As of SLF4J version 1.7.14, StaticMDCBinder classes shipping in various bindings + * come with a getSingleton() method. Previously only a public field called SINGLETON + * was available. + * + * @return MDCAdapter + * @throws NoClassDefFoundError in case no binding is available + * @since 1.7.14 + */ + private static MDCAdapter bwCompatibleGetMDCAdapterFromBinder() throws NoClassDefFoundError { + try { + return StaticMDCBinder.getSingleton().getMDCA(); + } catch (NoSuchMethodError nsme) { + // binding is probably a version of SLF4J older than 1.7.14 + return StaticMDCBinder.SINGLETON.getMDCA(); + } + } + static { try { - mdcAdapter = StaticMDCBinder.SINGLETON.getMDCA(); + mdcAdapter = bwCompatibleGetMDCAdapterFromBinder(); } catch (NoClassDefFoundError ncde) { mdcAdapter = new NOPMDCAdapter(); String msg = ncde.getMessage(); diff --git a/slf4j-api/src/main/java/org/slf4j/MarkerFactory.java b/slf4j-api/src/main/java/org/slf4j/MarkerFactory.java index 8d50698d..7eff41f6 100644 --- a/slf4j-api/src/main/java/org/slf4j/MarkerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/MarkerFactory.java @@ -42,17 +42,35 @@ import org.slf4j.impl.StaticMarkerBinder; * @author Ceki Gülcü */ public class MarkerFactory { - static IMarkerFactory markerFactory; + static IMarkerFactory MARKER_FACTORY; private MarkerFactory() { } + /** + * As of SLF4J version 1.7.14, StaticMarkerBinder classes shipping in various bindings + * come with a getSingleton() method. Previously only a public field called SINGLETON + * was available. + * + * @return IMarkerFactory + * @throws NoClassDefFoundError in case no binding is available + * @since 1.7.14 + */ + private static IMarkerFactory bwCompatibleGetMarkerFactoryFromBinder() throws NoClassDefFoundError { + try { + return StaticMarkerBinder.getSingleton().getMarkerFactory(); + } catch (NoSuchMethodError nsme) { + // binding is probably a version of SLF4J older than 1.7.14 + return StaticMarkerBinder.SINGLETON.getMarkerFactory(); + } + } + + // this is where the binding happens static { try { - markerFactory = StaticMarkerBinder.SINGLETON.getMarkerFactory(); + MARKER_FACTORY = bwCompatibleGetMarkerFactoryFromBinder(); } catch (NoClassDefFoundError e) { - markerFactory = new BasicMarkerFactory(); - + MARKER_FACTORY = new BasicMarkerFactory(); } catch (Exception e) { // we should never get here Util.report("Unexpected failure while binding MarkerFactory", e); @@ -68,7 +86,7 @@ public class MarkerFactory { * @return marker */ public static Marker getMarker(String name) { - return markerFactory.getMarker(name); + return MARKER_FACTORY.getMarker(name); } /** @@ -79,7 +97,7 @@ public class MarkerFactory { * @since 1.5.1 */ public static Marker getDetachedMarker(String name) { - return markerFactory.getDetachedMarker(name); + return MARKER_FACTORY.getDetachedMarker(name); } /** @@ -91,6 +109,6 @@ public class MarkerFactory { * @return the IMarkerFactory instance in use */ public static IMarkerFactory getIMarkerFactory() { - return markerFactory; + return MARKER_FACTORY; } } \ No newline at end of file diff --git a/slf4j-api/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-api/src/main/java/org/slf4j/impl/StaticMDCBinder.java index 4fd65f40..9c8acdb0 100644 --- a/slf4j-api/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-api/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -42,6 +42,16 @@ public class StaticMDCBinder { private StaticMDCBinder() { throw new UnsupportedOperationException("This code should never make it into the jar"); } + + /** + * 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 diff --git a/slf4j-api/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-api/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 0823b827..24f4a616 100644 --- a/slf4j-api/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-api/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -51,6 +51,16 @@ public class StaticMarkerBinder implements MarkerFactoryBinder { throw new UnsupportedOperationException("This code should never make it into the jar"); } + /** + * 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}. diff --git a/slf4j-api/src/test/java/org/slf4j/DoubleCheckedInt.java b/slf4j-api/src/test/java/org/slf4j/DoubleCheckedInt.java new file mode 100755 index 00000000..9aa86b07 --- /dev/null +++ b/slf4j-api/src/test/java/org/slf4j/DoubleCheckedInt.java @@ -0,0 +1,141 @@ +package org.slf4j; + +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; + +/** + * This class demonstrates that threads accessing the STATE variable always see a consistent value. + * + * During ongoing initialization the observed value is either ONGOING_INITIALIZATION + * or one of {SUCCESS, FAILURE}. + * + * Post initialization the observed value is always one of {SUCCESS, FAILURE}. + * + * See also http://jira.qos.ch/browse/SLF4J-167 + * + * @author ceki + * + */ +public class DoubleCheckedInt { + + final static int THREAD_COUNT = 10 + Runtime.getRuntime().availableProcessors() * 2; + final static int UNINITIALIZED_STATE = 0; + final static int ONGOING_INITIALIZATION = 1; + final static int SUCCESS = 2; + final static int FAILURE = 3; + final static int NUMBER_OF_STATES = FAILURE + 1; + + private static int STATE = UNINITIALIZED_STATE; + + public static int getState() { + if (STATE == 0) { + synchronized (DoubleCheckedInt.class) { + if (STATE == UNINITIALIZED_STATE) { + STATE = ONGOING_INITIALIZATION; + long r = System.nanoTime(); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + if (r % 2 == 0) { + STATE = SUCCESS; + } else { + STATE = FAILURE; + } + } + } + } + return STATE; + } + + static public void main(String[] args) throws InterruptedException, BrokenBarrierException { + StateAccessingThread[] preInitializationThreads = harness(); + check(preInitializationThreads, false); + + System.out.println("============"); + StateAccessingThread[] postInitializationThreads = harness(); + check(postInitializationThreads, true); + } + + private static StateAccessingThread[] harness() throws InterruptedException, BrokenBarrierException { + StateAccessingThread[] threads = new StateAccessingThread[THREAD_COUNT]; + final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); + for (int i = 0; i < THREAD_COUNT; i++) { + threads[i] = new StateAccessingThread(barrier); + threads[i].start(); + } + + barrier.await(); + for (int i = 0; i < THREAD_COUNT; i++) { + threads[i].join(); + } + return threads; + } + + private static void check(StateAccessingThread[] threads, boolean postInit) { + + int[] stateCount = getStateCount(threads); + printStateCount(stateCount); + + if (stateCount[UNINITIALIZED_STATE] != 0) { + throw new IllegalStateException("getState() should never return a zero value"); + } + + if (stateCount[SUCCESS] != 0 && stateCount[FAILURE] != 0) { + throw new IllegalStateException("getState() should return consistent values"); + } + + if (postInit) { + if (stateCount[SUCCESS] != THREAD_COUNT && stateCount[FAILURE] != THREAD_COUNT) { + throw new IllegalStateException("getState() should return consistent values"); + } + } + + } + + private static void printStateCount(int[] stateCount) { + for (int i = 0; i < NUMBER_OF_STATES; i++) { + switch (i) { + case UNINITIALIZED_STATE: + System.out.println("UNINITIALIZED_STATE count: " + stateCount[i]); + break; + case ONGOING_INITIALIZATION: + System.out.println("ONGOING_INITIALIZATION count: " + stateCount[i]); + break; + case SUCCESS: + System.out.println("SUCCESS count: " + stateCount[i]); + break; + case FAILURE: + System.out.println("FAILURE count: " + stateCount[i]); + break; + } + } + } + + private static int[] getStateCount(StateAccessingThread[] threads) { + int[] valCount = new int[NUMBER_OF_STATES]; + for (int i = 0; i < threads.length; i++) { + int val = threads[i].state; + valCount[val] = valCount[val] + 1; + } + return valCount; + } + + static class StateAccessingThread extends Thread { + public int state = -1; + final CyclicBarrier barrier; + + StateAccessingThread(CyclicBarrier barrier) { + this.barrier = barrier; + } + + public void run() { + try { + barrier.await(); + } catch (Exception e) { + e.printStackTrace(); + } + state = DoubleCheckedInt.getState(); + } + }; +} diff --git a/slf4j-jcl/src/main/java/org/slf4j/impl/JCLLoggerFactory.java b/slf4j-jcl/src/main/java/org/slf4j/impl/JCLLoggerFactory.java index 77ea88ec..79be1048 100644 --- a/slf4j-jcl/src/main/java/org/slf4j/impl/JCLLoggerFactory.java +++ b/slf4j-jcl/src/main/java/org/slf4j/impl/JCLLoggerFactory.java @@ -46,7 +46,7 @@ public class JCLLoggerFactory implements ILoggerFactory { static { try { Class.forName("org.apache.commons.logging.impl.SLF4JLogFactory"); - String part1 = "Detected both jcl-over-slf4j.jar AND slf4j-jcl.jar on the class path, preempting StackOverflowError. "; + String part1 = "Detected both jcl-over-slf4j.jar AND bound slf4j-jcl.jar on the class path, preempting StackOverflowError. "; String part2 = "See also " + JCL_DELEGATION_LOOP_URL + " for more details."; Util.report(part1); @@ -58,7 +58,7 @@ public class JCLLoggerFactory implements ILoggerFactory { } // key: name (String), value: a JCLLoggerAdapter; - ConcurrentMap loggerMap; + final ConcurrentMap loggerMap; public JCLLoggerFactory() { loggerMap = new ConcurrentHashMap(); diff --git a/slf4j-jcl/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-jcl/src/main/java/org/slf4j/impl/StaticMDCBinder.java index b35b89b0..d9945eb5 100644 --- a/slf4j-jcl/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-jcl/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -42,11 +42,22 @@ public class 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 NOPMDCAdapter}. * * @return instance of NOPMDCAdapter + * @since 1.7.14 */ public MDCAdapter getMDCA() { return new NOPMDCAdapter(); diff --git a/slf4j-jcl/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-jcl/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 1d255230..97935cb1 100644 --- a/slf4j-jcl/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-jcl/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -48,6 +48,16 @@ public class StaticMarkerBinder implements MarkerFactoryBinder { 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}. diff --git a/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMDCBinder.java index bff523db..753e83f2 100644 --- a/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -41,7 +41,17 @@ public class 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 BasicMDCAdapter}. diff --git a/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 1d255230..97935cb1 100644 --- a/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -48,6 +48,16 @@ public class StaticMarkerBinder implements MarkerFactoryBinder { 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}. diff --git a/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerFactory.java b/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerFactory.java index e801f9cc..6194bb7b 100644 --- a/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerFactory.java +++ b/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerFactory.java @@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.log4j.LogManager; +import org.slf4j.helpers.Util; import org.slf4j.ILoggerFactory; import org.slf4j.Logger; @@ -39,6 +40,23 @@ import org.slf4j.Logger; */ public class Log4jLoggerFactory 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-log4j12.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; diff --git a/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMDCBinder.java index 77742309..a0e815fd 100644 --- a/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -40,7 +40,17 @@ public class 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}. diff --git a/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 1d255230..97935cb1 100644 --- a/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -48,6 +48,16 @@ public class StaticMarkerBinder implements MarkerFactoryBinder { 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}. diff --git a/slf4j-nop/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-nop/src/main/java/org/slf4j/impl/StaticMDCBinder.java index 086b0169..35dc8d80 100644 --- a/slf4j-nop/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-nop/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -42,6 +42,16 @@ public class 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}. diff --git a/slf4j-nop/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-nop/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 1d255230..97935cb1 100644 --- a/slf4j-nop/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-nop/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -48,6 +48,16 @@ public class StaticMarkerBinder implements MarkerFactoryBinder { 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}. diff --git a/slf4j-simple/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-simple/src/main/java/org/slf4j/impl/StaticMDCBinder.java index 086b0169..a88f2bfc 100644 --- a/slf4j-simple/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-simple/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -42,6 +42,16 @@ public class 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}. diff --git a/slf4j-simple/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-simple/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 435a924b..ef1a9d90 100644 --- a/slf4j-simple/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-simple/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -48,7 +48,17 @@ public class StaticMarkerBinder implements MarkerFactoryBinder { 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}. diff --git a/slf4j-site/src/site/pages/codes.html b/slf4j-site/src/site/pages/codes.html index f331be3b..766dd0a5 100755 --- a/slf4j-site/src/site/pages/codes.html +++ b/slf4j-site/src/site/pages/codes.html @@ -323,10 +323,11 @@ class B extends A {

The purpose of slf4j-log4j12 module is to delegate or redirect calls made to an SLF4J logger to log4j. The purpose of the log4j-over-slf4j module is to redirect calls made to a log4j - logger to SLF4J. If both slf4j-log4j12.jar and - log4j-over-slf4j.jar are present on the class path, a - StackOverflowError will inevitably occur immediately - after the first invocation of an SLF4J or a log4j logger. + logger to SLF4J. If SLF4J is bound withslf4j-log4j12.jar + and log4j-over-slf4j.jar is also present on the class + path, a StackOverflowError will inevitably occur + immediately after the first invocation of an SLF4J or a log4j + logger.

Here is how the exception might look like:

@@ -371,11 +372,11 @@ class B extends A {

The purpose of slf4j-jcl module is to delegate or redirect calls made to an SLF4J logger to jakarta commons logging (JCL). The purpose of the jcl-over-slf4j module is to redirect - calls made to a JCL logger to SLF4J. If both - slf4j-jcl.jar and jcl-over-slf4j.jar are present - on the class path, then a StackOverflowError will - inevitably occur immediately after the first invocation of an - SLF4J or a JCL logger. + calls made to a JCL logger to SLF4J. If SLF4J is bound with + slf4j-jcl.jar and jcl-over-slf4j.jar is also + present on the class path, then a StackOverflowError + will inevitably occur immediately after the first invocation of an + SLF4J or a JCL logger.

Here is how the exception might look like:

diff --git a/slf4j-site/src/site/pages/news.html b/slf4j-site/src/site/pages/news.html index 8f4de96e..dcc4feac 100755 --- a/slf4j-site/src/site/pages/news.html +++ b/slf4j-site/src/site/pages/news.html @@ -29,6 +29,52 @@
+

xxx January, 2016 - Release of SLF4J 1.7.14

+ + +

The assignment of the INITIALIZATION_STATE variable in + LoggerFactory is now guaranteed to be consistent for + multi-thread initializations. More specifically, only one thread + will see INITIALIZATION_STATE as UNINITIALIZED with all other + threads observing either ONGOING_INITIALIZATION or the final result + of the initialization. However, SLF4J initialization is still + non-blocking and re-entrant, in the sense that if some thread tries + to obtain loggers during ongoing initialization by another (or + same) thread, instances of SubstituteLogger are + returned. This fixes SLF4J-167

. + + +

Moved delegation check loop from log4j-over-slf4j.jar + to slf4j-log4j12.jar for better targeted loop checks. The + rationale behind the change is explained by Frans Orsel in SLF4J-345 who also + provided the relevant pull request. +

+ +

During initialization the binding ambiguity check is skipped + under Android in order to improve performance. This change was + requested by Nitin Verma in SLF4J-328 who also + provided the relevant patch. +

+ +

The StaticMarkerBinder and + StaticMDCBinder classes shipping in various SLF4J + bindings now offer a getSingletion() method. The + org.slf4j.MDC and MarkerFactory classes + now perform binding by invoking the getSingleton() + method first and if in the presence of an older version of SLF4J + with said method missing, then by accessing the SINGLETON + field. This backward compatible change was requested by Rufus + Alexander in SLF4J-347 in order + to implement an SLF4J binding in Clojure, namely slf4j-timbre. +

+ +
+

10th of November, 2015 - Release of SLF4J 1.7.13