Currently, the check on delegation loop for log4j is done in the log4j-over-sl4fj.jar, whereas the same check for jcl is done in the slf4j-jcl.jar. This causes different behaviour for log4j and jcl:
- For log4j, if both log4j-over-slf4j.jar and slf4j-log4j12.jar are present on the classpath, an IllegalStateException is always thrown, even if slf4j-log4j12.jar is not chosen as the actual binding.
- For jcl, if both jcl-over-slf4j.jar and slf4j-jcl.jar are present on the classpath, an IllegalStateException is ONLY thrown when slf4j-jcl.jar is chosen as the actual binding. If, for example, logback is also on the classpath and is chosen as the actual binding, then (JCLLoggerFactory class in) slf4j-jcl.jar is never initialized and therefore the delegation loop is not executed.
The log4j behaviour causes an issue for my situation, where I want to redirect log4j logging to slf4j/logback, but my classpath also contains (an older version of) slf4j-log4j12.jar. The actual binding is logback, so there is no real conflict, i.e. no danger of a delegation loop/stack overflow. Still, I'm unable to redirect log4j logging via slf4j/logback using log4j-over-slf4j.jar.
I propose to move the delegation loop check from log4j-over-slf4j.jar to slf4j-log4j12.jar, so that the delegation loop check behaviour for log4j will be the same as for jcl.
As a side note, one could argue that the "Detected both log4j-over-slf4j.jar AND slf4j-log4j12.jar on the class path" error text (and current equivalent for jcl) are not 100% clear/correct as the detection would only be done (is only done in case of jcl) if both jars are on the classpath and slf4j-log4j12.jar is the actual binding. It could be considered to change the error text to "Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path".
Another, more elaborate, solution is described in
SLF4J-185, where it is proposed to check the type of the actual binding as part of the delegation loop check. WIth the above change, I don't think this would be needed.
I'm working with TIBCO software, specifically TIBCO BusinessWorks. My goal is to redirect all logging of the TIBCO BusinessWorks engine into SLF4J, so that I can do smart things with it (e.g. send it to Graylog/Logstash). The whole installation consists of many TIBCO products and each has a lot of jars/libraries including open source and proprietary ones. Some of those libraries are dependent on SLF4J. Over the multiple products, multiple versions of SLF4J are included, including the slf4j-log4j12.jar. The classpath used for the BusinessWorks engine contains about 4-5 bindings:
By adding slf4j 1.7.13 and logback 1.1.3 in front of the classpath, I'm able to override the older versions. But, where it goes wrong is the delegation loop check in the log4j-over-slf4j-1.7.13.jar that I add. It finds the older slf4j-log4j12-1.5.2.jars on the classpath and throws the IllegalStateException, even though there is no conflict as logback is chosen as the actual binding.
The obvious other way around this is to remove the older slf4j related jars, but that is something I cannot do as it is part of the standard product installation. Other applications in the same installation could be dependent on these jars and I am not redirecting logging for those. Also, standard installation policies do not allow me to do this.