Tuesday, March 25, 2014

JBoss AS 7 and SLF4J

As side project at work, I'm porting a Java Enterprise 5 Seam 2 application to JBoss AS 7 (7.2, to be precise).   This application uses SLF4J for logging, and I quickly realized that without some careful configuration, the SLF4J log messages can get discarded.   That's not so great when trying to troubleshoot deployment problems!

(Side note: to post XML inside a <pre> tag on Blogger, use an HTML Encoder like this one)

Anyway, here's what I ended up doing to get it to work:
  1. Don't use the provided SLF4J module from the container.   This will allow the application to use it's own version of SLF4J and logging implementation (e.g. Log4J).   I did this by adding the following exclusions to jboss-deployment-structure.xml (like this):
            <exclusions>
                ... other modules ...
                <module name="org.apache.log4j" />
                <module name="org.slf4j" />
                <module name="org.slf4j.impl" />
            </exclusions>
    
    • Make sure to exclude the implementation org.slf4j.impl as well, otherwise the app server will supply it's own. 
    • For EAR deployments, this needs to be repeated in the sub-deployment for the WAR as well.   See this JBoss community post.

  2. Include the slf4j-api, and slf4j implementation jars (e.g. slf4j-log4j12 and log4j) in the lib directory of the EAR. In my case, this is just making sure that the Maven module for the EAR doesn't exclude these. Verify by locating the files in the target EAR.

    In the EAR pom.xml, I added the following dependencies:

           <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <scope>runtime</scope> 
            </dependency>
    
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
            </dependency>
    

    In this case, the versions are specified in a dependency management pom.xml.   Also, you may need to change the scope to 'runtime' if the scope is set in the dependency management (to something else, like 'test').
  3. Put your log implementation config files where the implementation can see them.   For Lo4J, you can make a jar with log4j.xml in it, and put this in the lib directory of the ear.

Troubleshooting

Various things I encountered while setting this up...

No SLF4J Implementation


If you manage to exclude the SLF4J implementation, but the EAR doesn't contain one you may get this:

ERROR [stderr] (ServerService Thread Pool -- 65) SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
ERROR [stderr] (ServerService Thread Pool -- 65) SLF4J: Defaulting to no-operation (NOP) logger implementation
ERROR [stderr] (ServerService Thread Pool -- 65) SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

In this case, just make sure the desired SLF4J implementation class is in the EAR lib directory. For example, add it as a dependency in your pom.xml.

JBoss-Specific Logging Configuration


I had an old log4j.xml that had some references to some older JBoss-specific logging features like this:

    <category name="javax">
        <priority value="INFO" class="org.jboss.logging.log4j.JDKLevel"/>
    </category>

These references caused ClassNotFoundExeptions when Log4J was initializing. To resolve this, I simply commented out these elements.

Also, I replaced org.jboss.logging.appender.RollingFileAppender with org.apache.log4j.RollingFileAppender.
 

No comments:

Post a Comment