From a21401d25e0948fffb9a63bcdfb5ccfa6942e306 Mon Sep 17 00:00:00 2001 From: Chetan Mehrotra Date: Mon, 3 Feb 2014 11:38:27 +0530 Subject: [PATCH 1/9] SLF4j 311 - Enable swapping of NOPLogger in SubstituteLoggerFactory --- .../slf4j/helpers/SubstitutableLogger.java | 314 ++++++++++++++++++ .../helpers/SubstituteLoggerFactory.java | 38 ++- .../helpers/SubstitutableLoggerTest.java | 107 ++++++ .../helpers/SubstituteLoggerFactoryTest.java | 70 ++++ 4 files changed, 520 insertions(+), 9 deletions(-) create mode 100644 slf4j-api/src/main/java/org/slf4j/helpers/SubstitutableLogger.java create mode 100644 slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java create mode 100644 slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/SubstitutableLogger.java b/slf4j-api/src/main/java/org/slf4j/helpers/SubstitutableLogger.java new file mode 100644 index 000000000..468d53bbe --- /dev/null +++ b/slf4j-api/src/main/java/org/slf4j/helpers/SubstitutableLogger.java @@ -0,0 +1,314 @@ +/** + * 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.helpers; + +import org.slf4j.Logger; +import org.slf4j.Marker; + +/** + * A helper class which delegates all calls to different Loggers. This enables + * swapping of the Logger implementation later. + * + * @author Chetan Mehrotra + */ +public class SubstitutableLogger implements Logger { + + private final String name; + + private volatile Logger _delegate; + + public SubstitutableLogger(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public boolean isTraceEnabled() { + return delegate().isTraceEnabled(); + } + + public void trace(String msg) { + delegate().trace(msg); + } + + public void trace(String format, Object arg) { + delegate().trace(format, arg); + } + + public void trace(String format, Object arg1, Object arg2) { + delegate().trace(format, arg1, arg2); + } + + public void trace(String format, Object... arguments) { + delegate().trace(format, arguments); + } + + public void trace(String msg, Throwable t) { + delegate().trace(msg, t); + } + + public boolean isTraceEnabled(Marker marker) { + return delegate().isTraceEnabled(marker); + } + + public void trace(Marker marker, String msg) { + delegate().trace(marker, msg); + } + + public void trace(Marker marker, String format, Object arg) { + delegate().trace(marker, format, arg); + } + + public void trace(Marker marker, String format, Object arg1, Object arg2) { + delegate().trace(marker, format, arg1, arg2); + } + + public void trace(Marker marker, String format, Object... arguments) { + delegate().trace(marker, format, arguments); + } + + public void trace(Marker marker, String msg, Throwable t) { + delegate().trace(marker, msg, t); + } + + public boolean isDebugEnabled() { + return delegate().isDebugEnabled(); + } + + public void debug(String msg) { + delegate().debug(msg); + } + + public void debug(String format, Object arg) { + delegate().debug(format, arg); + } + + public void debug(String format, Object arg1, Object arg2) { + delegate().debug(format, arg1, arg2); + } + + public void debug(String format, Object... arguments) { + delegate().debug(format, arguments); + } + + public void debug(String msg, Throwable t) { + delegate().debug(msg, t); + } + + public boolean isDebugEnabled(Marker marker) { + return delegate().isDebugEnabled(marker); + } + + public void debug(Marker marker, String msg) { + delegate().debug(marker, msg); + } + + public void debug(Marker marker, String format, Object arg) { + delegate().debug(marker, format, arg); + } + + public void debug(Marker marker, String format, Object arg1, Object arg2) { + delegate().debug(marker, format, arg1, arg2); + } + + public void debug(Marker marker, String format, Object... arguments) { + delegate().debug(marker, format, arguments); + } + + public void debug(Marker marker, String msg, Throwable t) { + delegate().debug(marker, msg, t); + } + + public boolean isInfoEnabled() { + return delegate().isInfoEnabled(); + } + + public void info(String msg) { + delegate().info(msg); + } + + public void info(String format, Object arg) { + delegate().info(format, arg); + } + + public void info(String format, Object arg1, Object arg2) { + delegate().info(format, arg1, arg2); + } + + public void info(String format, Object... arguments) { + delegate().info(format, arguments); + } + + public void info(String msg, Throwable t) { + delegate().info(msg, t); + } + + public boolean isInfoEnabled(Marker marker) { + return delegate().isInfoEnabled(marker); + } + + public void info(Marker marker, String msg) { + delegate().info(marker, msg); + } + + public void info(Marker marker, String format, Object arg) { + delegate().info(marker, format, arg); + } + + public void info(Marker marker, String format, Object arg1, Object arg2) { + delegate().info(marker, format, arg1, arg2); + } + + public void info(Marker marker, String format, Object... arguments) { + delegate().info(marker, format, arguments); + } + + public void info(Marker marker, String msg, Throwable t) { + delegate().info(marker, msg, t); + } + + public boolean isWarnEnabled() { + return delegate().isWarnEnabled(); + } + + public void warn(String msg) { + delegate().warn(msg); + } + + public void warn(String format, Object arg) { + delegate().warn(format, arg); + } + + public void warn(String format, Object arg1, Object arg2) { + delegate().warn(format, arg1, arg2); + } + + public void warn(String format, Object... arguments) { + delegate().warn(format, arguments); + } + + public void warn(String msg, Throwable t) { + delegate().warn(msg, t); + } + + public boolean isWarnEnabled(Marker marker) { + return delegate().isWarnEnabled(marker); + } + + public void warn(Marker marker, String msg) { + delegate().warn(marker, msg); + } + + public void warn(Marker marker, String format, Object arg) { + delegate().warn(marker, format, arg); + } + + public void warn(Marker marker, String format, Object arg1, Object arg2) { + delegate().warn(marker, format, arg1, arg2); + } + + public void warn(Marker marker, String format, Object... arguments) { + delegate().warn(marker, format, arguments); + } + + public void warn(Marker marker, String msg, Throwable t) { + delegate().warn(marker, msg, t); + } + + public boolean isErrorEnabled() { + return delegate().isErrorEnabled(); + } + + public void error(String msg) { + delegate().error(msg); + } + + public void error(String format, Object arg) { + delegate().error(format, arg); + } + + public void error(String format, Object arg1, Object arg2) { + delegate().error(format, arg1, arg2); + } + + public void error(String format, Object... arguments) { + delegate().error(format, arguments); + } + + public void error(String msg, Throwable t) { + delegate().error(msg, t); + } + + public boolean isErrorEnabled(Marker marker) { + return delegate().isErrorEnabled(marker); + } + + public void error(Marker marker, String msg) { + delegate().error(marker, msg); + } + + public void error(Marker marker, String format, Object arg) { + delegate().error(marker, format, arg); + } + + public void error(Marker marker, String format, Object arg1, Object arg2) { + delegate().error(marker, format, arg1, arg2); + } + + public void error(Marker marker, String format, Object... arguments) { + delegate().error(marker, format, arguments); + } + + public void error(Marker marker, String msg, Throwable t) { + delegate().error(marker, msg, t); + } + + public void setDelegate(Logger delegate) { + this._delegate = delegate; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + SubstitutableLogger that = (SubstitutableLogger) o; + + if (!name.equals(that.name)) return false; + + return true; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + Logger delegate() { + return _delegate != null ? _delegate : NOPLogger.NOP_LOGGER; + } +} 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 7382ed793..223606ea5 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java @@ -26,6 +26,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.slf4j.ILoggerFactory; import org.slf4j.Logger; @@ -33,32 +35,50 @@ /** * SubstituteLoggerFactory is an trivial implementation of * {@link ILoggerFactory} which always returns the unique instance of NOPLogger. - * + *

*

* It used as a temporary substitute for the real ILoggerFactory during its * auto-configuration which may re-enter LoggerFactory to obtain logger * instances. See also http://bugzilla.slf4j.org/show_bug.cgi?id=106 - * + *

+ *

+ * Logger implementations can swap out the NOPLogger with actual Logger + * implementation once they are properly configured by changing the delegate + * in {@link org.slf4j.helpers.SubstitutableLogger} + *

+ * * @author Ceki Gülcü */ public class SubstituteLoggerFactory implements ILoggerFactory { // keep a record of requested logger names - final List loggerNameList = new ArrayList(); + final ConcurrentMap loggers = new ConcurrentHashMap(); public Logger getLogger(String name) { - synchronized (loggerNameList) { - loggerNameList.add(name); + SubstitutableLogger logger; + synchronized (loggers) { + logger = loggers.get(name); + if (logger == null) { + logger = new SubstitutableLogger(name); + loggers.put(name, logger); + } } - return NOPLogger.NOP_LOGGER; + return logger; } public List getLoggerNameList() { - List copy = new ArrayList(); - synchronized (loggerNameList) { - copy.addAll(loggerNameList); + List copy = new ArrayList(); + synchronized (loggers) { + copy.addAll(loggers.keySet()); } return copy; } + public Iterable getLoggers() { + return loggers.values(); + } + + public void clear() { + loggers.clear(); + } } diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java new file mode 100644 index 000000000..f3f55246f --- /dev/null +++ b/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java @@ -0,0 +1,107 @@ +/** + * 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.helpers; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import junit.framework.TestCase; +import org.slf4j.Logger; + +/** + * @author Chetan Mehrotra + */ +public class SubstitutableLoggerTest extends TestCase { + private static final Set EXCLUDED_METHODS = new HashSet(Arrays.asList("getName")); + + public void testDelegate() throws Exception { + SubstitutableLogger log = new SubstitutableLogger("foo"); + assertTrue(log.delegate() instanceof NOPLogger); + + Set methodSignatures = determinemethodSignatures(Logger.class); + LoggerInvocationHandler ih = new LoggerInvocationHandler(); + Logger proxyLogger = (Logger) Proxy.newProxyInstance(getClass().getClassLoader(), + new Class[]{Logger.class}, ih); + log.setDelegate(proxyLogger); + + invokeMethods(log); + + //Assert that all methods are delegated + methodSignatures.removeAll(ih.getMethodSignatures()); + if (!methodSignatures.isEmpty()) { + fail("Following methods are not delegated " + methodSignatures.toString()); + } + } + + private void invokeMethods(Logger proxyLogger) throws InvocationTargetException, IllegalAccessException { + for (Method m : Logger.class.getDeclaredMethods()) { + if (!EXCLUDED_METHODS.contains(m.getName())) { + m.invoke(proxyLogger, new Object[m.getParameterTypes().length]); + } + } + } + + private class LoggerInvocationHandler implements InvocationHandler { + private final Set methodSignatures = new HashSet(); + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + methodSignatures.add(getMethodSignature(method)); + if (method.getName().startsWith("is")) { + return true; + } + return null; + } + + public Set getMethodSignatures() { + return methodSignatures; + } + } + + private static Set determinemethodSignatures(Class loggerClass) { + Set methodSignatures = new HashSet(); + for (Method m : loggerClass.getDeclaredMethods()) { + if (!EXCLUDED_METHODS.contains(m.getName())) { + methodSignatures.add(getMethodSignature(m)); + } + } + return methodSignatures; + } + + private static String getMethodSignature(Method m) { + List result = new ArrayList(); + result.add(m.getName()); + for (Class clazz : m.getParameterTypes()) { + result.add(clazz.getSimpleName()); + } + return result.toString(); + } +} diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java new file mode 100644 index 000000000..c6c5a486a --- /dev/null +++ b/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java @@ -0,0 +1,70 @@ +/** + * 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.helpers; + +import junit.framework.TestCase; +import org.slf4j.Logger; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class SubstituteLoggerFactoryTest extends TestCase{ + private SubstituteLoggerFactory factory = new SubstituteLoggerFactory(); + + public void testFactory() { + Logger log = factory.getLogger("foo"); + assertNotNull(log); + + Logger log2 = factory.getLogger("foo"); + assertTrue("Loggers with same name must be same",log == log2); + } + + @SuppressWarnings("unchecked") + public void testLoggerNameList() { + factory.getLogger("foo1"); + factory.getLogger("foo2"); + + Set expectedNames = new HashSet(Arrays.asList("foo1","foo2")); + Set actualNames = new HashSet(factory.getLoggerNameList()); + + assertEquals(expectedNames, actualNames); + } + + public void testLoggers() { + factory.getLogger("foo1"); + factory.getLogger("foo2"); + + Set expectedNames = new HashSet(Arrays.asList("foo1","foo2")); + + Set actualNames = new HashSet(); + for(SubstitutableLogger slog : factory.getLoggers()){ + actualNames.add(slog.getName()); + } + + assertEquals(expectedNames, actualNames); + } + +} From 78280dc391f27e3ec41e8902f51a7d32a944a362 Mon Sep 17 00:00:00 2001 From: Chetan Mehrotra Date: Mon, 3 Feb 2014 21:53:55 +0530 Subject: [PATCH 2/9] Minor changes around method names --- .../slf4j/helpers/SubstitutableLoggerTest.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) 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 f3f55246f..67d354702 100644 --- a/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java +++ b/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java @@ -47,7 +47,7 @@ public void testDelegate() throws Exception { SubstitutableLogger log = new SubstitutableLogger("foo"); assertTrue(log.delegate() instanceof NOPLogger); - Set methodSignatures = determinemethodSignatures(Logger.class); + Set expectedMethodSignatures = determineMethodSignatures(Logger.class); LoggerInvocationHandler ih = new LoggerInvocationHandler(); Logger proxyLogger = (Logger) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Logger.class}, ih); @@ -56,9 +56,9 @@ public void testDelegate() throws Exception { invokeMethods(log); //Assert that all methods are delegated - methodSignatures.removeAll(ih.getMethodSignatures()); - if (!methodSignatures.isEmpty()) { - fail("Following methods are not delegated " + methodSignatures.toString()); + expectedMethodSignatures.removeAll(ih.getInvokedMethodSignatures()); + if (!expectedMethodSignatures.isEmpty()) { + fail("Following methods are not delegated " + expectedMethodSignatures.toString()); } } @@ -71,22 +71,22 @@ private void invokeMethods(Logger proxyLogger) throws InvocationTargetException, } private class LoggerInvocationHandler implements InvocationHandler { - private final Set methodSignatures = new HashSet(); + private final Set invokedMethodSignatures = new HashSet(); public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - methodSignatures.add(getMethodSignature(method)); + invokedMethodSignatures.add(getMethodSignature(method)); if (method.getName().startsWith("is")) { return true; } return null; } - public Set getMethodSignatures() { - return methodSignatures; + public Set getInvokedMethodSignatures() { + return invokedMethodSignatures; } } - private static Set determinemethodSignatures(Class loggerClass) { + private static Set determineMethodSignatures(Class loggerClass) { Set methodSignatures = new HashSet(); for (Method m : loggerClass.getDeclaredMethods()) { if (!EXCLUDED_METHODS.contains(m.getName())) { From ca685554866dd3134f344a2b8effd5a0f38c9a31 Mon Sep 17 00:00:00 2001 From: Chetan Mehrotra Date: Mon, 3 Feb 2014 21:57:34 +0530 Subject: [PATCH 3/9] Removing the synchronisation as per Andrei comments --- .../org/slf4j/helpers/SubstituteLoggerFactory.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) 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 223606ea5..f23569a89 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java @@ -67,15 +67,11 @@ public Logger getLogger(String name) { } public List getLoggerNameList() { - List copy = new ArrayList(); - synchronized (loggers) { - copy.addAll(loggers.keySet()); - } - return copy; + return new ArrayList(loggers.keySet()); } - public Iterable getLoggers() { - return loggers.values(); + public List getLoggers() { + return new ArrayList(loggers.values()); } public void clear() { From 4f1bf59089529a4ab386ab9270bdd58374ac36dc Mon Sep 17 00:00:00 2001 From: Chetan Mehrotra Date: Mon, 3 Feb 2014 21:59:28 +0530 Subject: [PATCH 4/9] Changing the delegate of substituted loggers post initialization --- .../main/java/org/slf4j/LoggerFactory.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java index 3994188f8..6bd7bafc4 100644 --- a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java @@ -29,6 +29,7 @@ import java.util.*; import org.slf4j.helpers.NOPLoggerFactory; +import org.slf4j.helpers.SubstitutableLogger; import org.slf4j.helpers.SubstituteLoggerFactory; import org.slf4j.helpers.Util; import org.slf4j.impl.StaticLoggerBinder; @@ -128,7 +129,7 @@ private final static void bind() { StaticLoggerBinder.getSingleton(); INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION; reportActualBinding(staticLoggerBinderPathSet); - emitSubstituteLoggerWarning(); + fixSubstitutedLoggers(); } catch (NoClassDefFoundError ncde) { String msg = ncde.getMessage(); if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) { @@ -161,18 +162,24 @@ static void failedBinding(Throwable t) { Util.report("Failed to instantiate SLF4J LoggerFactory", t); } - private final static void emitSubstituteLoggerWarning() { - List loggerNameList = TEMP_FACTORY.getLoggerNameList(); - if (loggerNameList.size() == 0) { + private final static void fixSubstitutedLoggers() { + List loggers = TEMP_FACTORY.getLoggers(); + + if(loggers.isEmpty()){ return; } - Util.report("The following loggers will not work because they were created"); - Util.report("during the default configuration phase of the underlying logging system."); + + Util.report("The following set of substitute loggers may have been accessed"); + Util.report("during the initialization phase and logging calls during this"); + Util.report("phase were not honored but that calls in the future to these loggers"); + Util.report("will be honored."); Util.report("See also " + SUBSTITUTE_LOGGER_URL); - for (int i = 0; i < loggerNameList.size(); i++) { - String loggerName = (String) loggerNameList.get(i); - Util.report(loggerName); + for(SubstitutableLogger subLogger : loggers){ + subLogger.setDelegate(getLogger(subLogger.getName())); + Util.report(subLogger.getName()); } + + TEMP_FACTORY.clear(); } private final static void versionSanityCheck() { From c529cbd123ca4569ca656b1ba9a288acca1f92c1 Mon Sep 17 00:00:00 2001 From: Chetan Mehrotra Date: Mon, 3 Feb 2014 22:14:23 +0530 Subject: [PATCH 5/9] Updated the details around substituable logger creation as per updated implementation --- slf4j-site/src/site/pages/codes.html | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/slf4j-site/src/site/pages/codes.html b/slf4j-site/src/site/pages/codes.html index cfbbf9c64..cb3248563 100755 --- a/slf4j-site/src/site/pages/codes.html +++ b/slf4j-site/src/site/pages/codes.html @@ -409,30 +409,18 @@

Substitute loggers NullPointerException.

To avoid this chicken-and-egg problem, SLF4J substitutes a - no-operation logger factory during this initialization - phase. However, the substitute loggers returned during this phase - are not operational. They are nop implementations. + substitutable logger which initially delegates to no-operation logger factory + during this initialization phase. Later after the LoggerFactory initialization + is completed then the delegates in the SubstituteLoggers are replaced with actual + logger implementations.

If any substitute logger had to be created, SLF4J will emit a - warning listing such nop loggers. This warning is intended to let - you know that you should not expect any logging output from these - loggers. + a listing of such loggers. This list is intended to let + you know that some of the initial logging statements from these + loggers might have been missed

-

To obtain output from the listed loggers, isolate the - components invoking these loggers and to exclude them from the - default configuration. Once default configuration is finished, - those excluded components can be configured in a second-step - configuration. In principle, both logback and log4j allow - multi-step configuration. For logback, second-step configuration - is described in the - relevant section.. -

- -

If you are not interested in the output from any of the - substitute loggers, then no action is required on your part.

From 8f28a83eb4f6b81dd46e53052e17df3aaf602347 Mon Sep 17 00:00:00 2001 From: Ceki Gulcu Date: Mon, 3 Feb 2014 20:05:23 +0100 Subject: [PATCH 6/9] fix buf 311 --- .../main/java/org/slf4j/LoggerFactory.java | 12 +- .../slf4j/helpers/SubstitutableLogger.java | 314 ----------------- .../org/slf4j/helpers/SubstituteLogger.java | 325 ++++++++++++++++++ .../helpers/SubstituteLoggerFactory.java | 35 +- .../helpers/SubstitutableLoggerTest.java | 2 +- .../helpers/SubstituteLoggerFactoryTest.java | 2 +- slf4j-scala-api/src/main/scala/A.scala | 8 + slf4j-site/src/site/pages/codes.html | 29 +- slf4j-site/src/site/pages/news.html | 10 + 9 files changed, 375 insertions(+), 362 deletions(-) delete mode 100644 slf4j-api/src/main/java/org/slf4j/helpers/SubstitutableLogger.java create mode 100644 slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLogger.java create mode 100644 slf4j-scala-api/src/main/scala/A.scala diff --git a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java index 6bd7bafc4..361411081 100644 --- a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java @@ -29,7 +29,7 @@ import java.util.*; import org.slf4j.helpers.NOPLoggerFactory; -import org.slf4j.helpers.SubstitutableLogger; +import org.slf4j.helpers.SubstituteLogger; import org.slf4j.helpers.SubstituteLoggerFactory; import org.slf4j.helpers.Util; import org.slf4j.impl.StaticLoggerBinder; @@ -163,18 +163,18 @@ static void failedBinding(Throwable t) { } private final static void fixSubstitutedLoggers() { - List loggers = TEMP_FACTORY.getLoggers(); + List loggers = TEMP_FACTORY.getLoggers(); if(loggers.isEmpty()){ return; } Util.report("The following set of substitute loggers may have been accessed"); - Util.report("during the initialization phase and logging calls during this"); - Util.report("phase were not honored but that calls in the future to these loggers"); - Util.report("will be honored."); + Util.report("during the initialization phase. Logging calls during this"); + Util.report("phase were not honored. However, subsequent logging calls to these"); + Util.report("loggers will work as normally expected."); Util.report("See also " + SUBSTITUTE_LOGGER_URL); - for(SubstitutableLogger subLogger : loggers){ + for(SubstituteLogger subLogger : loggers){ subLogger.setDelegate(getLogger(subLogger.getName())); Util.report(subLogger.getName()); } diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/SubstitutableLogger.java b/slf4j-api/src/main/java/org/slf4j/helpers/SubstitutableLogger.java deleted file mode 100644 index 468d53bbe..000000000 --- a/slf4j-api/src/main/java/org/slf4j/helpers/SubstitutableLogger.java +++ /dev/null @@ -1,314 +0,0 @@ -/** - * 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.helpers; - -import org.slf4j.Logger; -import org.slf4j.Marker; - -/** - * A helper class which delegates all calls to different Loggers. This enables - * swapping of the Logger implementation later. - * - * @author Chetan Mehrotra - */ -public class SubstitutableLogger implements Logger { - - private final String name; - - private volatile Logger _delegate; - - public SubstitutableLogger(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public boolean isTraceEnabled() { - return delegate().isTraceEnabled(); - } - - public void trace(String msg) { - delegate().trace(msg); - } - - public void trace(String format, Object arg) { - delegate().trace(format, arg); - } - - public void trace(String format, Object arg1, Object arg2) { - delegate().trace(format, arg1, arg2); - } - - public void trace(String format, Object... arguments) { - delegate().trace(format, arguments); - } - - public void trace(String msg, Throwable t) { - delegate().trace(msg, t); - } - - public boolean isTraceEnabled(Marker marker) { - return delegate().isTraceEnabled(marker); - } - - public void trace(Marker marker, String msg) { - delegate().trace(marker, msg); - } - - public void trace(Marker marker, String format, Object arg) { - delegate().trace(marker, format, arg); - } - - public void trace(Marker marker, String format, Object arg1, Object arg2) { - delegate().trace(marker, format, arg1, arg2); - } - - public void trace(Marker marker, String format, Object... arguments) { - delegate().trace(marker, format, arguments); - } - - public void trace(Marker marker, String msg, Throwable t) { - delegate().trace(marker, msg, t); - } - - public boolean isDebugEnabled() { - return delegate().isDebugEnabled(); - } - - public void debug(String msg) { - delegate().debug(msg); - } - - public void debug(String format, Object arg) { - delegate().debug(format, arg); - } - - public void debug(String format, Object arg1, Object arg2) { - delegate().debug(format, arg1, arg2); - } - - public void debug(String format, Object... arguments) { - delegate().debug(format, arguments); - } - - public void debug(String msg, Throwable t) { - delegate().debug(msg, t); - } - - public boolean isDebugEnabled(Marker marker) { - return delegate().isDebugEnabled(marker); - } - - public void debug(Marker marker, String msg) { - delegate().debug(marker, msg); - } - - public void debug(Marker marker, String format, Object arg) { - delegate().debug(marker, format, arg); - } - - public void debug(Marker marker, String format, Object arg1, Object arg2) { - delegate().debug(marker, format, arg1, arg2); - } - - public void debug(Marker marker, String format, Object... arguments) { - delegate().debug(marker, format, arguments); - } - - public void debug(Marker marker, String msg, Throwable t) { - delegate().debug(marker, msg, t); - } - - public boolean isInfoEnabled() { - return delegate().isInfoEnabled(); - } - - public void info(String msg) { - delegate().info(msg); - } - - public void info(String format, Object arg) { - delegate().info(format, arg); - } - - public void info(String format, Object arg1, Object arg2) { - delegate().info(format, arg1, arg2); - } - - public void info(String format, Object... arguments) { - delegate().info(format, arguments); - } - - public void info(String msg, Throwable t) { - delegate().info(msg, t); - } - - public boolean isInfoEnabled(Marker marker) { - return delegate().isInfoEnabled(marker); - } - - public void info(Marker marker, String msg) { - delegate().info(marker, msg); - } - - public void info(Marker marker, String format, Object arg) { - delegate().info(marker, format, arg); - } - - public void info(Marker marker, String format, Object arg1, Object arg2) { - delegate().info(marker, format, arg1, arg2); - } - - public void info(Marker marker, String format, Object... arguments) { - delegate().info(marker, format, arguments); - } - - public void info(Marker marker, String msg, Throwable t) { - delegate().info(marker, msg, t); - } - - public boolean isWarnEnabled() { - return delegate().isWarnEnabled(); - } - - public void warn(String msg) { - delegate().warn(msg); - } - - public void warn(String format, Object arg) { - delegate().warn(format, arg); - } - - public void warn(String format, Object arg1, Object arg2) { - delegate().warn(format, arg1, arg2); - } - - public void warn(String format, Object... arguments) { - delegate().warn(format, arguments); - } - - public void warn(String msg, Throwable t) { - delegate().warn(msg, t); - } - - public boolean isWarnEnabled(Marker marker) { - return delegate().isWarnEnabled(marker); - } - - public void warn(Marker marker, String msg) { - delegate().warn(marker, msg); - } - - public void warn(Marker marker, String format, Object arg) { - delegate().warn(marker, format, arg); - } - - public void warn(Marker marker, String format, Object arg1, Object arg2) { - delegate().warn(marker, format, arg1, arg2); - } - - public void warn(Marker marker, String format, Object... arguments) { - delegate().warn(marker, format, arguments); - } - - public void warn(Marker marker, String msg, Throwable t) { - delegate().warn(marker, msg, t); - } - - public boolean isErrorEnabled() { - return delegate().isErrorEnabled(); - } - - public void error(String msg) { - delegate().error(msg); - } - - public void error(String format, Object arg) { - delegate().error(format, arg); - } - - public void error(String format, Object arg1, Object arg2) { - delegate().error(format, arg1, arg2); - } - - public void error(String format, Object... arguments) { - delegate().error(format, arguments); - } - - public void error(String msg, Throwable t) { - delegate().error(msg, t); - } - - public boolean isErrorEnabled(Marker marker) { - return delegate().isErrorEnabled(marker); - } - - public void error(Marker marker, String msg) { - delegate().error(marker, msg); - } - - public void error(Marker marker, String format, Object arg) { - delegate().error(marker, format, arg); - } - - public void error(Marker marker, String format, Object arg1, Object arg2) { - delegate().error(marker, format, arg1, arg2); - } - - public void error(Marker marker, String format, Object... arguments) { - delegate().error(marker, format, arguments); - } - - public void error(Marker marker, String msg, Throwable t) { - delegate().error(marker, msg, t); - } - - public void setDelegate(Logger delegate) { - this._delegate = delegate; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - SubstitutableLogger that = (SubstitutableLogger) o; - - if (!name.equals(that.name)) return false; - - return true; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - Logger delegate() { - return _delegate != null ? _delegate : NOPLogger.NOP_LOGGER; - } -} diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLogger.java b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLogger.java new file mode 100644 index 000000000..d7cfedfdf --- /dev/null +++ b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLogger.java @@ -0,0 +1,325 @@ +/** + * 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.helpers; + +import org.slf4j.Logger; +import org.slf4j.Marker; + +/** + * A logger implementation which logs via a delegate logger. By default, the delegate is a + * {@link NOPLogger}. However, a different delegate can be set at anytime. + *

+ * See also the relevant + * error code documentation. + * + * @author Chetan Mehrotra + */ +public class SubstituteLogger implements Logger { + + private final String name; + + private volatile Logger _delegate; + + public SubstituteLogger(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public boolean isTraceEnabled() { + return delegate().isTraceEnabled(); + } + + public void trace(String msg) { + delegate().trace(msg); + } + + public void trace(String format, Object arg) { + delegate().trace(format, arg); + } + + public void trace(String format, Object arg1, Object arg2) { + delegate().trace(format, arg1, arg2); + } + + public void trace(String format, Object... arguments) { + delegate().trace(format, arguments); + } + + public void trace(String msg, Throwable t) { + delegate().trace(msg, t); + } + + public boolean isTraceEnabled(Marker marker) { + return delegate().isTraceEnabled(marker); + } + + public void trace(Marker marker, String msg) { + delegate().trace(marker, msg); + } + + public void trace(Marker marker, String format, Object arg) { + delegate().trace(marker, format, arg); + } + + public void trace(Marker marker, String format, Object arg1, Object arg2) { + delegate().trace(marker, format, arg1, arg2); + } + + public void trace(Marker marker, String format, Object... arguments) { + delegate().trace(marker, format, arguments); + } + + public void trace(Marker marker, String msg, Throwable t) { + delegate().trace(marker, msg, t); + } + + public boolean isDebugEnabled() { + return delegate().isDebugEnabled(); + } + + public void debug(String msg) { + delegate().debug(msg); + } + + public void debug(String format, Object arg) { + delegate().debug(format, arg); + } + + public void debug(String format, Object arg1, Object arg2) { + delegate().debug(format, arg1, arg2); + } + + public void debug(String format, Object... arguments) { + delegate().debug(format, arguments); + } + + public void debug(String msg, Throwable t) { + delegate().debug(msg, t); + } + + public boolean isDebugEnabled(Marker marker) { + return delegate().isDebugEnabled(marker); + } + + public void debug(Marker marker, String msg) { + delegate().debug(marker, msg); + } + + public void debug(Marker marker, String format, Object arg) { + delegate().debug(marker, format, arg); + } + + public void debug(Marker marker, String format, Object arg1, Object arg2) { + delegate().debug(marker, format, arg1, arg2); + } + + public void debug(Marker marker, String format, Object... arguments) { + delegate().debug(marker, format, arguments); + } + + public void debug(Marker marker, String msg, Throwable t) { + delegate().debug(marker, msg, t); + } + + public boolean isInfoEnabled() { + return delegate().isInfoEnabled(); + } + + public void info(String msg) { + delegate().info(msg); + } + + public void info(String format, Object arg) { + delegate().info(format, arg); + } + + public void info(String format, Object arg1, Object arg2) { + delegate().info(format, arg1, arg2); + } + + public void info(String format, Object... arguments) { + delegate().info(format, arguments); + } + + public void info(String msg, Throwable t) { + delegate().info(msg, t); + } + + public boolean isInfoEnabled(Marker marker) { + return delegate().isInfoEnabled(marker); + } + + public void info(Marker marker, String msg) { + delegate().info(marker, msg); + } + + public void info(Marker marker, String format, Object arg) { + delegate().info(marker, format, arg); + } + + public void info(Marker marker, String format, Object arg1, Object arg2) { + delegate().info(marker, format, arg1, arg2); + } + + public void info(Marker marker, String format, Object... arguments) { + delegate().info(marker, format, arguments); + } + + public void info(Marker marker, String msg, Throwable t) { + delegate().info(marker, msg, t); + } + + public boolean isWarnEnabled() { + return delegate().isWarnEnabled(); + } + + public void warn(String msg) { + delegate().warn(msg); + } + + public void warn(String format, Object arg) { + delegate().warn(format, arg); + } + + public void warn(String format, Object arg1, Object arg2) { + delegate().warn(format, arg1, arg2); + } + + public void warn(String format, Object... arguments) { + delegate().warn(format, arguments); + } + + public void warn(String msg, Throwable t) { + delegate().warn(msg, t); + } + + public boolean isWarnEnabled(Marker marker) { + return delegate().isWarnEnabled(marker); + } + + public void warn(Marker marker, String msg) { + delegate().warn(marker, msg); + } + + public void warn(Marker marker, String format, Object arg) { + delegate().warn(marker, format, arg); + } + + public void warn(Marker marker, String format, Object arg1, Object arg2) { + delegate().warn(marker, format, arg1, arg2); + } + + public void warn(Marker marker, String format, Object... arguments) { + delegate().warn(marker, format, arguments); + } + + public void warn(Marker marker, String msg, Throwable t) { + delegate().warn(marker, msg, t); + } + + public boolean isErrorEnabled() { + return delegate().isErrorEnabled(); + } + + public void error(String msg) { + delegate().error(msg); + } + + public void error(String format, Object arg) { + delegate().error(format, arg); + } + + public void error(String format, Object arg1, Object arg2) { + delegate().error(format, arg1, arg2); + } + + public void error(String format, Object... arguments) { + delegate().error(format, arguments); + } + + public void error(String msg, Throwable t) { + delegate().error(msg, t); + } + + public boolean isErrorEnabled(Marker marker) { + return delegate().isErrorEnabled(marker); + } + + public void error(Marker marker, String msg) { + delegate().error(marker, msg); + } + + public void error(Marker marker, String format, Object arg) { + delegate().error(marker, format, arg); + } + + public void error(Marker marker, String format, Object arg1, Object arg2) { + delegate().error(marker, format, arg1, arg2); + } + + public void error(Marker marker, String format, Object... arguments) { + delegate().error(marker, format, arguments); + } + + public void error(Marker marker, String msg, Throwable t) { + delegate().error(marker, msg, t); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + SubstituteLogger that = (SubstituteLogger) o; + + if (!name.equals(that.name)) return false; + + return true; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + /** + * Return the delegate logger instance if set. Otherwise, return a {@link NOPLogger} + * instance. + */ + Logger delegate() { + return _delegate != null ? _delegate : NOPLogger.NOP_LOGGER; + } + + /** + * Typically called after the {@link org.slf4j.LoggerFactory} initialization phase is completed. + * @param delegate + */ + public void setDelegate(Logger delegate) { + this._delegate = delegate; + } +} 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 f23569a89..a54fcabd1 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java @@ -33,36 +33,21 @@ import org.slf4j.Logger; /** - * SubstituteLoggerFactory is an trivial implementation of - * {@link ILoggerFactory} which always returns the unique instance of NOPLogger. - *

- *

- * It used as a temporary substitute for the real ILoggerFactory during its - * auto-configuration which may re-enter LoggerFactory to obtain logger - * instances. See also http://bugzilla.slf4j.org/show_bug.cgi?id=106 - *

- *

- * Logger implementations can swap out the NOPLogger with actual Logger - * implementation once they are properly configured by changing the delegate - * in {@link org.slf4j.helpers.SubstitutableLogger} - *

- * + * SubstituteLoggerFactory manages instances of {@link SubstituteLogger}. * @author Ceki Gülcü */ public class SubstituteLoggerFactory implements ILoggerFactory { - // keep a record of requested logger names - final ConcurrentMap loggers = new ConcurrentHashMap(); + final ConcurrentMap loggers = new ConcurrentHashMap(); public Logger getLogger(String name) { - SubstitutableLogger logger; - synchronized (loggers) { - logger = loggers.get(name); - if (logger == null) { - logger = new SubstitutableLogger(name); - loggers.put(name, logger); + SubstituteLogger logger = loggers.get(name); + if (logger == null) { + logger = new SubstituteLogger(name); + SubstituteLogger oldLogger = loggers.putIfAbsent(name, logger); + if (oldLogger != null) + logger = oldLogger; } - } return logger; } @@ -70,8 +55,8 @@ public List getLoggerNameList() { return new ArrayList(loggers.keySet()); } - public List getLoggers() { - return new ArrayList(loggers.values()); + public List getLoggers() { + return new ArrayList(loggers.values()); } public void clear() { 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 67d354702..3055b7ee2 100644 --- a/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java +++ b/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java @@ -44,7 +44,7 @@ public class SubstitutableLoggerTest extends TestCase { private static final Set EXCLUDED_METHODS = new HashSet(Arrays.asList("getName")); public void testDelegate() throws Exception { - SubstitutableLogger log = new SubstitutableLogger("foo"); + SubstituteLogger log = new SubstituteLogger("foo"); assertTrue(log.delegate() instanceof NOPLogger); Set expectedMethodSignatures = determineMethodSignatures(Logger.class); diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java index c6c5a486a..7acb43c97 100644 --- a/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java +++ b/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java @@ -60,7 +60,7 @@ public void testLoggers() { Set expectedNames = new HashSet(Arrays.asList("foo1","foo2")); Set actualNames = new HashSet(); - for(SubstitutableLogger slog : factory.getLoggers()){ + for(SubstituteLogger slog : factory.getLoggers()){ actualNames.add(slog.getName()); } diff --git a/slf4j-scala-api/src/main/scala/A.scala b/slf4j-scala-api/src/main/scala/A.scala new file mode 100644 index 000000000..3a9d44ca4 --- /dev/null +++ b/slf4j-scala-api/src/main/scala/A.scala @@ -0,0 +1,8 @@ +/* + * Created by IntelliJ IDEA. + * User: ceki + * Date: 03.05.11 + * Time: 09:03 + */ +package ; +public scala class A { } \ No newline at end of file diff --git a/slf4j-site/src/site/pages/codes.html b/slf4j-site/src/site/pages/codes.html index cb3248563..e28a3a3aa 100755 --- a/slf4j-site/src/site/pages/codes.html +++ b/slf4j-site/src/site/pages/codes.html @@ -401,29 +401,28 @@

Substitute loggers

Highly configurable logging systems such as logback and log4j may create components which invoke loggers during their own initialization. See issue lbcore-47 for a + href="http://jira.qos.ch/browse/LOGBACK-127">LOGBACK-127 for a typical occurrence. However, since the binding process with SLF4J has not yet completed (because the underlying logging system was not yet completely loaded into memory), it is not possible to - honor such logger creation requests, resulting in a - NullPointerException.

- -

To avoid this chicken-and-egg problem, SLF4J substitutes a - substitutable logger which initially delegates to no-operation logger factory - during this initialization phase. Later after the LoggerFactory initialization - is completed then the delegates in the SubstituteLoggers are replaced with actual - logger implementations. + honor such logger creation requests.

+ +

To avoid this chicken-and-egg problem, SLF4J creates substitute + loggers during this phase (initialization). Calls made to the + substitute loggers during this phase are simply dropped. After the + initialization completes, the substitute logger will delegate + logging calls to the appropriate logger implementation and + otherwise will function as any other logger returned by + LoggerFactory.

-

If any substitute logger had to be created, SLF4J will emit a - a listing of such loggers. This list is intended to let - you know that some of the initial logging statements from these - loggers might have been missed +

If any substitute logger had to be created, SLF4J will emit a a + listing of such loggers. This list is intended to let you know + that any logging calls made to these loggers during initialization + have been dropped.

- - diff --git a/slf4j-site/src/site/pages/news.html b/slf4j-site/src/site/pages/news.html index 7b187b97d..4afbff2be 100755 --- a/slf4j-site/src/site/pages/news.html +++ b/slf4j-site/src/site/pages/news.html @@ -33,6 +33,16 @@

, 2013 - Release of SLF4J 1.7.6

Added slf4j-android module to the slf4j distribution. This module is contributed by Andrey Korzhevskiy.

+ +

Loggers created during the initialization phase are no longer + NOPLoggers which drop all logging calls. Instead, + SLF4J now creates substitute loggers which delegate to the + appropriate logger implementation after the initilization phase + completes. Only calls made to these loggers during the + initialization phase are dropped. This enhacement was proposed in + bug 311 + by Chetan Mehrotra. +

Concunrrency improvement in BasicMarkerFactory. This improvement was contributed From 99da14c2fc1044170f585068da07356d2f92acbc Mon Sep 17 00:00:00 2001 From: Ceki Gulcu Date: Mon, 3 Feb 2014 20:07:12 +0100 Subject: [PATCH 7/9] remove ununsed slf4j-scala-api --- slf4j-scala-api/src/main/scala/A.scala | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 slf4j-scala-api/src/main/scala/A.scala diff --git a/slf4j-scala-api/src/main/scala/A.scala b/slf4j-scala-api/src/main/scala/A.scala deleted file mode 100644 index 3a9d44ca4..000000000 --- a/slf4j-scala-api/src/main/scala/A.scala +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Created by IntelliJ IDEA. - * User: ceki - * Date: 03.05.11 - * Time: 09:03 - */ -package ; -public scala class A { } \ No newline at end of file From 7a7d0f8c525d74c8f3e39455fac9c9bc3283fad8 Mon Sep 17 00:00:00 2001 From: Ceki Gulcu Date: Mon, 3 Feb 2014 21:06:23 +0100 Subject: [PATCH 8/9] update mailing list links --- slf4j-site/src/site/pages/mailing-lists.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/slf4j-site/src/site/pages/mailing-lists.html b/slf4j-site/src/site/pages/mailing-lists.html index 5a5a6f886..096114695 100755 --- a/slf4j-site/src/site/pages/mailing-lists.html +++ b/slf4j-site/src/site/pages/mailing-lists.html @@ -70,7 +70,6 @@

slf4j-announcements list


Archives: Pipermail | - MARC | Nabble

The announcements list is reserved for important SLF4J API @@ -91,11 +90,12 @@

slf4j-user list

Unsubscribe
Archives: - Pipermail | + qos.ch | + MarkLogic | Gmane | - MARC | Nabble | - MailArchive + MailArchive +

@@ -114,9 +114,9 @@

slf4j-dev list

Unsubscribe
Archives: - Pipermail | + qos.ch | + MarkLogic | Gmane | - MARC | Nabble | MailArchive

From f56ee2ea37af6a22710b74142477b245a65aee18 Mon Sep 17 00:00:00 2001 From: Ceki Gulcu Date: Mon, 3 Feb 2014 21:21:14 +0100 Subject: [PATCH 9/9] minor changes --- .../helpers/SubstituteLoggerFactory.java | 22 ++++++++++--------- .../helpers/SubstituteLoggerFactoryTest.java | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) mode change 100644 => 100755 slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java mode change 100644 => 100755 slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java old mode 100644 new mode 100755 index a54fcabd1..77d86540f --- a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java @@ -24,17 +24,19 @@ */ package org.slf4j.helpers; +import org.slf4j.ILoggerFactory; +import org.slf4j.Logger; + import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import org.slf4j.ILoggerFactory; -import org.slf4j.Logger; - /** * SubstituteLoggerFactory manages instances of {@link SubstituteLogger}. + * * @author Ceki Gülcü + * @author Chetan Mehrotra */ public class SubstituteLoggerFactory implements ILoggerFactory { @@ -42,16 +44,16 @@ public class SubstituteLoggerFactory implements ILoggerFactory { public Logger getLogger(String name) { SubstituteLogger logger = loggers.get(name); - if (logger == null) { - logger = new SubstituteLogger(name); - SubstituteLogger oldLogger = loggers.putIfAbsent(name, logger); - if (oldLogger != null) - logger = oldLogger; - } + if (logger == null) { + logger = new SubstituteLogger(name); + SubstituteLogger oldLogger = loggers.putIfAbsent(name, logger); + if (oldLogger != null) + logger = oldLogger; + } return logger; } - public List getLoggerNameList() { + public List getLoggerNames() { return new ArrayList(loggers.keySet()); } diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java old mode 100644 new mode 100755 index 7acb43c97..435da25a8 --- a/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java +++ b/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java @@ -48,7 +48,7 @@ public void testLoggerNameList() { factory.getLogger("foo2"); Set expectedNames = new HashSet(Arrays.asList("foo1","foo2")); - Set actualNames = new HashSet(factory.getLoggerNameList()); + Set actualNames = new HashSet(factory.getLoggerNames()); assertEquals(expectedNames, actualNames); }