- preparing release 1.5.11

- added code to detect the simultaneous presence of both
log4j-over-slf4j.jar and slf4j-log4j12.jar. See also
http://slf4j.org/codes.html#log4jDelegationLoop

- added code to detect the simultaneous presence of both
jcl-over-slf4j.jar and slf4j-jcl.jar. See also
http://slf4j.org/codes.html#jclDelegationLoop

- Fixed http://bugzilla.slf4j.org/show_bug.cgi?id=168
This commit is contained in:
Ceki Gulcu 2010-02-25 12:42:32 +01:00
parent 99c9eb8a75
commit dae55b8229
31 changed files with 193 additions and 40 deletions

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -45,6 +45,8 @@ public class Category {
protected org.slf4j.Logger slf4jLogger;
private org.slf4j.spi.LocationAwareLogger locationAwareLogger;
private static Marker FATAL_MARKER = MarkerFactory.getMarker("FATAL");
Category(String name) {

View File

@ -18,6 +18,8 @@ package org.apache.log4j;
import java.util.Hashtable;
import org.slf4j.helpers.Util;
/**
* This class is a factory that creates and maintains org.apache.log4j.Loggers
* wrapping org.slf4j.Loggers.
@ -32,12 +34,30 @@ class Log4jLoggerFactory {
// String, Logger
private static Hashtable log4jLoggers = new Hashtable();
private static final String LOG4J_DELEGATION_LOOP_URL = "http://www.slf4j.org/codes.html#log4jDelegationLoop";
// check for delegation loops
static {
try {
Class.forName("org.slf4j.impl.Log4jLoggerFactory");
String part1 = "Detected both log4j-over-slf4j.jar AND slf4j-log4j12.jar on the class path, preempting StackOverflowError. ";
String part2 = "See also " + LOG4J_DELEGATION_LOOP_URL
+ " for more details.";
Util.reportFailure(part1);
Util.reportFailure(part2);
throw new IllegalStateException(part1 + part2);
} catch (ClassNotFoundException e) {
// this is the good case
}
}
public static synchronized Logger getLogger(String name) {
if (log4jLoggers.containsKey(name)) {
return (org.apache.log4j.Logger) log4jLoggers.get(name);
} else {
Logger log4jLogger = new Logger(name);
log4jLoggers.put(name, log4jLogger);
return log4jLogger;
}

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
<packaging>pom</packaging>
<name>SLF4J</name>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -85,7 +85,7 @@ public final class LoggerFactory {
* compatibility. Thus, 1.5.7-SNAPSHOT, 1.5.7.RC0 are compatible with 1.5.7.
*/
static private final String[] API_COMPATIBILITY_LIST = new String[] {
"1.5.5", "1.5.6", "1.5.7", "1.5.8", "1.5.9", "1.5.10" };
"1.5.5", "1.5.6", "1.5.7", "1.5.8", "1.5.9", "1.5.10", "1.5.11" };
// private constructor prevents instantiation
private LoggerFactory() {

View File

@ -61,7 +61,7 @@ public class StaticLoggerBinder {
* The value of this field is usually modified with each release.
*/
// to avoid constant folding by the compiler, this field must *not* be final
public static String REQUESTED_API_VERSION = "1.5.10"; // !final
public static String REQUESTED_API_VERSION = "1.5.11"; // !final
private StaticLoggerBinder() {
throw new UnsupportedOperationException("This code should have never made it into the jar");

View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -39,6 +39,7 @@ import java.util.Map;
import org.apache.commons.logging.LogFactory;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.helpers.Util;
/**
* JCLLoggerFactory is an implementation of {@link ILoggerFactory} returning the
@ -48,6 +49,24 @@ import org.slf4j.Logger;
*/
public class JCLLoggerFactory implements ILoggerFactory {
private static final String JCL_DELEGATION_LOOP_URL = "http://www.slf4j.org/codes.html#jclDelegationLoop";
// check for delegation loops
static {
try {
Class.forName("org.apache.commons.logging.impl.SLF4JLogFactory");
String part1 = "Detected both jcl-over-slf4j.jar AND slf4j-jcl.jar on the class path, preempting StackOverflowError. ";
String part2 = "See also " + JCL_DELEGATION_LOOP_URL
+ " for more details.";
Util.reportFailure(part1);
Util.reportFailure(part2);
throw new IllegalStateException(part1 + part2);
} catch (ClassNotFoundException e) {
// this is the good case
}
}
// key: name (String), value: a JCLLoggerAdapter;
Map loggerMap;

View File

@ -65,7 +65,7 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
*/
//to avoid constant folding by the compiler, this field must *not* be final
public static String REQUESTED_API_VERSION = "1.5.10";
public static String REQUESTED_API_VERSION = "1.5.11";
// Binding specific code:
private static final String loggerFactoryClassStr = JCLLoggerFactory.class

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -66,7 +66,7 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
* The value of this field is usually modified with each release.
*/
// to avoid constant folding by the compiler, this field must *not* be final
public static String REQUESTED_API_VERSION = "1.5.10"; // !final
public static String REQUESTED_API_VERSION = "1.5.11"; // !final
private static final String loggerFactoryClassStr = org.slf4j.impl.JDK14LoggerFactory.class.getName();

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -66,7 +66,7 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
* against. The value of this field is usually modified with each release.
*/
// to avoid constant folding by the compiler, this field must *not* be final
public static String REQUESTED_API_VERSION = "1.5.10"; // !final
public static String REQUESTED_API_VERSION = "1.5.11"; // !final
private static final String loggerFactoryClassStr = Log4jLoggerFactory.class
.getName();

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -66,7 +66,7 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
* The value of this field is usually modified with each release.
*/
// to avoid constant folding by the compiler, this field must *not* be final
public static String REQUESTED_API_VERSION = "1.5.10"; // !final
public static String REQUESTED_API_VERSION = "1.5.11"; // !final
private static final String loggerFactoryClassStr = NOPLoggerFactory.class.getName();

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -58,7 +58,7 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
* against. The value of this field is usually modified with each release.
*/
// to avoid constant folding by the compiler, this field must *not* be final
public static String REQUESTED_API_VERSION = "1.5.10"; // !final
public static String REQUESTED_API_VERSION = "1.5.11"; // !final
private static final String loggerFactoryClassStr = SimpleLoggerFactory.class.getName();

View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -1,11 +1,13 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>SLF4J Error Codes</title>
<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>SLF4J Error Codes</title>
<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
<link rel="stylesheet" type="text/css" href="css/prettify.css" />
</head>
<body>
<body onload="prettyPrint()">
<script type="text/javascript" src="js/prettify.js"></script>
<script type="text/javascript">prefix='';</script>
<script src="templates/header.js" type="text/javascript"></script>
@ -13,6 +15,7 @@
<script src="templates/left.js" type="text/javascript"></script>
</div>
<div id="content">
<center>
@ -151,7 +154,7 @@
<em>slf4j-simple-${version}.jar</em> and
<em>slf4j-nop-${version}.jar</em> on the class path and you wish
to use the nop (no-operation) binding, then remove
<em>slf4j-simple-${version}.jar</em> from the class parh.</p>
<em>slf4j-simple-${version}.jar</em> from the class path.</p>
<!-- ====================================================== -->
@ -168,7 +171,102 @@
an effective remedy.
</p>
<!-- ====================================================== -->
<h3>
<a name="log4jDelegationLoop"
href="#log4jDelegationLoop">Detected both log4j-over-slf4j.jar
AND slf4j-log4j12.jar on the class path, preempting
<code>StackOverflowError</code>.</a>
</h3>
<p>The purpose of slf4j-log4j12 module is to delegate or redirect
calls made to an SLF4J logger to log4j. The purpose of the
log4j-over-slf4j module is to redirect calls made to a log4j
logger to SLF4J. If both <em>slf4j-log4j12.jar</em> and
<em>log4j-over-slf4j.jar</em> are present on the class path, a
<code>StackOverflowError</code> will inevitably occur immediately
after the first invocation of an SLF4J or a log4j logger.
</p>
<p>Here is how the exception might look like:</p>
<pre class="prettyprint source">Exception in thread "main" java.lang.StackOverflowError
at java.util.Hashtable.containsKey(Hashtable.java:306)
at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:36)
at org.apache.log4j.LogManager.getLogger(LogManager.java:39)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:73)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:249)
at org.apache.log4j.Category.&lt;init>(Category.java:53)
at org.apache.log4j.Logger..&lt;init>(Logger.java:35)
at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:39)
at org.apache.log4j.LogManager.getLogger(LogManager.java:39)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:73)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:249)
at org.apache.log4j.Category..&lt;init>(Category.java:53)
at org.apache.log4j.Logger..&lt;init>(Logger.java:35)
at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:39)
at org.apache.log4j.LogManager.getLogger(LogManager.java:39)
subsequent lines omitted...</pre>
<p>As of SLF4J version 1.5.11, the code preempts the inevitable
stack overflow error by throwing an exception with details about
the actual cause of the problem. This is deemed to be better than
leaving the user wondering about the reasons of the
<code>StackOverflowError</code>.
</p>
<p>For more background on this topic see <a
href="legacy.html">Bridging legacy APIs</a>.
</p>
<!-- ====================================================== -->
<h3>
<a name="jclDelegationLoop" href="#jclDelegationLoop">Detected
both jcl-over-slf4j.jar AND slf4j-jcl.jar on the class path,
preempting <code>StackOverflowError</code>.</a>
</h3>
<p>The purpose of slf4j-jcl module is to delegate or redirect
calls made to an SLF4J logger to jakarta commons logging
(JCL). The purpose of the jcl-over-slf4j module is to redirect
calls made to a JCL logger to SLF4J. If both
<em>slf4j-jcl.jar</em> and <em>jcl-over-slf4j.jar</em> are present
on the class path, then a <code>StackOverflowError</code> will
inevitably occur immediately after the first invocation of an
SLF4J or a JCL logger.
</p>
<p>Here is how the exception might look like:</p>
<pre class="prettyprint source">Exception in thread "main" java.lang.StackOverflowError
at java.lang.String.hashCode(String.java:1482)
at java.util.HashMap.get(HashMap.java:300)
at org.slf4j.impl.JCLLoggerFactory.getLogger(JCLLoggerFactory.java:67)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:249)
at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:155)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:289)
at org.slf4j.impl.JCLLoggerFactory.getLogger(JCLLoggerFactory.java:69)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:249)
at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:155)
subsequent lines omitted...</pre>
<p>As of SLF4J version 1.5.11, the code preempts the inevitable
stack overflow error by throwing an exception with details about
the actual cause of the problem. This is deemed to be better than
leaving the user wondering about the reasons of the
<code>StackOverflowError</code>.
</p>
<p>For more background on this topic see <a
href="legacy.html">Bridging legacy APIs</a>.
</p>
<!-- ====================================================== -->
<h3>
<a name="no_static_mdc_binder"
href="#no_static_mdc_binder">Failed to load class

View File

@ -101,10 +101,10 @@
<p>Please note that <em>jcl-over-slf4j.jar</em> and
<em>slf4j-jcl.jar</em> cannot be deployed at the same time. The
former jar file will cause JCL to delegate the choice of the logging
system to SLF4J and the latter jar file will cause SLF4J to delegate
the choice of the logging system to JCL, resulting in an infinite
loop.
former jar file will cause JCL to delegate the choice of the
logging system to SLF4J and the latter jar file will cause SLF4J
to delegate the choice of the logging system to JCL, resulting in
an <a href="codes.html#jclDelegationLoop">infinite loop</a>.
</p>
@ -184,9 +184,10 @@
<p>The presence of <em>slf4j-logj12.jar</em>, that is the log4j
binding for SLF4J, will force all SLF4J calls to be delegated to
log4j. The presence of <em>log4j-over-slf4j.jar</em> will in turn
delegate all log4j API calls to their SLF4J equivalents. If both are
present simultaneously, slf4j calls will be delegated to log4j, and
log4j calls redirected to SLF4j, resulting in an endless loop.
delegate all log4j API calls to their SLF4J equivalents. If both
are present simultaneously, slf4j calls will be delegated to
log4j, and log4j calls redirected to SLF4j, resulting in an <a
href="codes.html#log4jDelegationLoop">endless loop</a>.
</p>
<h3><a name="jul-to-slf4j" href="jul-to-slf4j">JUL to SLF4J</a></h3>

View File

@ -27,7 +27,20 @@
<hr noshade="noshade" size="1"/>
<h3>March xx, 2010 - Release of SLF4J 1.5.11</h3>
<h3>February 25th, 2010 - Release of SLF4J 1.5.11</h3>
<p>Users yet unfamiliar with SLF4J sometimes unknowingly place both
<em>log4j-over-slf4j.jar</em> and <em>slf4j-log4j12.jar</em>
simultanously on the class path causing stack overflow
errors. Simultaneously placing both <em>jcl-over-slf4j.jar</em> and
<em>slf4j-jcl.jar</em> on the class path, is another occurrence of
the same general problem. As of this version, SLF4J preempts the
inevitable stack overflow error by throwing an exception with
details about the actual cause of the problem. This is deemed to be
better than leaving the user wondering about the reasons of the
<code>StackOverflowError</code>.
</p>
<p>Fixed <a href="http://bugzilla.slf4j.org/show_bug.cgi?id=168">bug
168</a>. In case log4j-over-slf4j is used and a logback appender