Notes from the field on ColdFusion (or related) technical issues.

Friday, January 25, 2013

ColdFusion 9 and SLF4J/Log4J Errors

I've been having some problems trying to incorporate ActiveMQ with CF9, mainly because of logger conflicts; CF tries to use and old version of Log4J with SLF4J, and this creates problems with later versions of SLF4J.  Some parts of CF appear to be bound directly to Log4J, however, so simply replacing Log4J is not an option.

Errors include:
  • "java.lang.ClassNotFoundException: org.slf4j.impl.StaticLoggerBinder" 
  • "SLF4J: This version of SLF4J requires log4j version 1.2.12 or later."
  • "java.lang.ExceptionInInitializerError at org.apache.activemq.ActiveMQConnection."

One of the really nice things about SLF4J is that it's designed to be replaced at *runtime*. Things compile against SLF4J, but then you (as systems administrator) can choose what implementation will do the actual logging, be it Java's own logger or something like Log4j. It's important to note that the original author of Log4J has abandoned that project and replaced it with a new logging implementation, called LOGBack.  So, we'll do exactly that: change SLF4J to log via LOGBack.


I wound up gutting and replacing SLF4J with a newer version that's backward-compatible, and using LOGBack as the actual logging implementation (instead of Log4J).

The directories involved will vary based on whether you're using a "standalone" or "multiserver" install.  There are a few directories involved, and I'll express them by name:

"ColdFusion lib directory":
  • standalone: coldfusion9/lib, or
  • mulitserver: jrun4/servers/[servername]/cfusion.ear/cfusion.war/WEB-INF/cfusion/lib
"Web app lib directory":
  • standalone: coldfusion9/wwwroot/web-inf/lib
  • mulitserver: jrun4/servers/[servername]/cfusion.ear/cfusion.war/WEB-INF/lib (notice "cfusion" disappeared)
"Web app classes directory":
  • standalone: coldfusion9/wwwroot/web-inf/classes
  • mulitserver: jrun4/servers/[servername]/cfusion.ear/cfusion.war/WEB-INF/classes
Here's the step by step:

1. Download SLF4J from http://www.slf4j.org/download.html and LOGBack from http://logback.qos.ch/download.html

2. Stop ColdFusion.  Otherwise, you won't be able to rename the jars in next step.

3. In your ColdFusion lib directory, rename* or delete the following files:
  • slf4j-api-1.5.6.jar --> slf4j-api-1.5.6.jar.old
  • slf4j-log4j12-1.5.6.jar --> slf4j-log4j12-1.5.6.jar.old
* do NOT rename them to .old.jar, or they will still be in the classpath!

This step has the effect of removing ColdFusion's current SLF4J implementation.

4. Place the new SLF4J implementation jar in the web app lib directory:
  • slf4j-api-1.7.2.jar
5. Place the LOGBack implementation jars in the  web app lib directory:
  • logback-core-1.0.9.jar
  • logback-classic-1.0.9.jar
6. Create a file named "logback.xml" in your web app classes directory, with the following contents:
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>
  <root level="info">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
(If you don't create a logback.xml to change your root logging level to level="info" the amount of logging will likely bring a busy server to its knees.)

7. Start ColdFusion

Now you can place any other jars you need (eg, ActiveMQ.jar) in the web app lib directory and you won't get SLF4J errors.