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);
}