Logback and Jboss 7 - don't work together?
Asked Answered
P

4

43

I am having a curious problem. I had this Java application which was previously deployed in tomcat and happily used logback classic as an slf4j implementation. Now when we tried to deploy the same app in a jboss 7.1.final server it doesn't even deploy the application maoning about java.lang.ClassCastException: org.slf4j.impl.Slf4jLoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext This is the offending line of code

final LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

The class that has his is spring injected and that is failing - hence the whole application cannot be deployed. Anyone got a solution to this? Thanks in advance

After looking in this site plus other forums I realised that Jboss 7 comes bundled with it's own slf4j implementation and implement the same ILoggerFactory interface that LoggerContext in logback does. Our application tried to get an instance of the same but the app server imposes it's own slf4j implementation.

I tried to modify the module.xml in jboss\modules\org\slf4j\impl\main and pointed it to logback jars.

<resources>
    <resource-root path="logback-classic-0.9.28.jar"/>
    <resource-root path="logback-core-0.9.28.jar"/>
</resources>

Now when I start the application I am getting a serious error

Exception starting filter WicketFilter: java.lang.ClassCastException: ch.qos.logback.classic.LoggerContext cannot be cast to ch.qos.logback.classic.LoggerContext

I am at my wits end. Any jboss and logback experts can help? Thanks in advance

Plateau answered 1/3, 2012 at 15:13 Comment(2)
Are you having logback*.jar in both /lib directory and in EAR/WAR?Gully
Hi Tomasz. I am having logback jars in my WEB-INF/lib directory of my war file. As mentioned above I have changed the module.xml in my jboss org.slf4j.Impl module to point logback jars (classic & core) both of which are in the same folder as the module.xml.Plateau
A
64

You need to exclude the servers version of slf4j from your deployment. Create a jboss-deployment-structure.xml file and place it in either your WARS META-INF or WEB-INF directory.

The contents of the file should look like this:

<jboss-deployment-structure>
    <deployment>
        <!-- Exclusions allow you to prevent the server from automatically adding some dependencies     -->
        <exclusions>
            <module name="org.slf4j" />
            <module name="org.slf4j.impl" />
        </exclusions>
    </deployment>
</jboss-deployment-structure>
Apnea answered 1/3, 2012 at 17:9 Comment(14)
Workd a treat! Thanks. I guess we can exclude any module that we don't want using this file. Thanks againPlateau
@James R. Perkins I also get that problem but it is my won class. Example com.java.User. I get the problem when I redeployed the war file without restart the Jboss 7 Server. How can solve it?Convergent
@CycDemo it should work. If not something could be leaking out if your getting ClassCastException. What version of JBoss AS 7?Apnea
@James R. Perkins, I use JBoss AS 7.1.1 FinalConvergent
Not sure what it could be then. I know that others are successfully doing this. Maybe post a new question on the forums, community.jboss.org/en/jbossas7/content, or here with more details.Apnea
it didn't work for me still getting same error ... java.lang.ClassCastException: org.slf4j.impl.Slf4jLoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();Thad
Where did you put the jboss-deployment-structure.xml in your deployment.Apnea
@Hassan, I have exact same ClassCastException with Wildfly 10.1.0. I tried to use jboss-deployment-structure.xml to exclude (as mentioned in this post) the servers module but its not working. I'm deploying an EAR. Tried putting jboss-deployment-structure.xml in WEB-INF of my WAR and also the META-INF of my EAR. No matter were I put it still getting the ClassCastException. Were you able to successfully do it?Pocketbook
For an EAR it needs to be in the EAR/META-INF directory and each subdeployment where the exclusion is required needs to be defined. For WIldFly 10 have a look at the add-logging-api-dependencies attribute as well.Apnea
Excluding individual modules didn't work for me. Instead, I excluded the logging subsystem and that resolved my issue.Pocketbook
Problem is that, by doing this way, jboss deployment logs also get logged in the new logfile and, what's worst, they appear to be wrong. For example I get "successfully deployed %s": this log showed in the usual server.log but contained the .war name..Edo
That seems odd. Are you including logback in your deployment?Apnea
@JamesR.Perkins How can I do the same trick with JBoss [The Oracle] 5.1.0.GA? I try to deploy jar file.Unpretentious
I'm not too sure. I'm not familiar with that version of JBoss.Apnea
B
7

If you are using the bridges for jul or jcl in your app, you should exclude them too:

        <module name="org.slf4j" />
        <module name="org.slf4j.jcl-over-slf4j" />
        <module name="org.slf4j.impl" />
        <module name="org.jboss.logging.jul-to-slf4j-stub" />
Brigidabrigit answered 30/10, 2013 at 23:22 Comment(0)
P
7

There is alternative approach:

  • you got logging configured in your war
  • you got all dependencies in your war
  • you don't configure anything in JBoss server directory, not even additional JBoss modules

Just disable JBoss logging completely and rely on the dependencies in your war. Edit your jboss-deployment-structure.xml as follows:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
    <deployment>
        <exclusions>
            <module name="org.apache.commons.logging" />
            <module name="org.apache.log4j" />
            <module name="org.jboss.logging" />
            <module name="org.jboss.logging.jul-to-slf4j-stub" />
            <module name="org.jboss.logmanager" />
            <module name="org.jboss.logmanager.log4j" />
            <module name="org.slf4j" />
            <module name="org.slf4j.impl" />
            <module name="org.slf4j.jcl-over-slf4j" />
        </exclusions>
    </deployment>
</jboss-deployment-structure>

Once you deploy your app, bootstrap logging (boot.log) keeps working also server.log will show deployment logging. But all your application is logged through your (in this example) slf4j+logback in your war.

Note that you should not need to run JBoss with -Dorg.jboss.logging.provider=slf4j, if you specify this, you will need to provide JBoss modules (typically slf4j-api, logback-classic and logback-core), but it is not worth the effort, as JBoss logging is now used only for bootstrap (boot.log) and for deployment info (server.log).

References:
http://tinyapps.blogspot.com/2013/01/getting-logback-and-slf4j-to-work-in.html
https://mcmap.net/q/379963/-logback-and-jboss-7-don-39-t-work-together

Planetary answered 27/6, 2016 at 16:22 Comment(0)
E
0

To make independent logging with Logback + Json in JBoss EAP 7.0 I need to exclude outdated Jackson implementation too:

jboss-deployment-structure.xml

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
    <deployment>
        <!-- https://docs.jboss.org/author/display/AS7/Class%20Loading%20in%20AS7.html -->
        <!-- https://docs.wildfly.org/16/Developer_Guide.html -->
        <exclusions>
            <!-- Rely on WAR's SLF4j + Logback instead of JBoss logmananger. -->
            <module name="org.apache.commons.logging" />
            <module name="org.apache.log4j" />
            <module name="org.jboss.as.logging" />
            <module name="org.jboss.logging" />
            <module name="org.jboss.logging.jul-to-slf4j-stub" />
            <module name="org.jboss.logmanager" />
            <module name="org.jboss.log4j.logmanager" />
            <module name="org.slf4j" />
            <module name="org.slf4j.ext" />
            <module name="org.slf4j.impl" />
            <module name="org.slf4j.jcl-over-slf4j" />
            <!-- Built-in Jackson is without the field: Feature.USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING, need to bundle own version. -->
            <!-- https://docs.jboss.org/resteasy/docs/3.0.2.Final/userguide/html/json.html -->
            <module name="org.jboss.resteasy.resteasy-jackson-provider"/>
            <module name="org.jboss.resteasy.resteasy-jackson2-provider"/>
        </exclusions>
    </deployment>
</jboss-deployment-structure>

pom.xml

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>${slf4j.version}</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>${slf4j.version}</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jul-to-slf4j</artifactId>
    <version>${slf4j.version}</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.9</version>
</dependency>
<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>7.0.1</version>
</dependency>

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <charset>UTF-8</charset>
            <pattern>%d{HH:mm:ss.SSS} %5p [%15.15t] %logger %m%ex</pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <charset>UTF-8</charset>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [%t] %-40.40logger{39} %m%n%ex</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${my.log.dir}/test-servlet-logging-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>500MB</totalSizeCap>
        </rollingPolicy>
    </appender>

    <appender name="JSON-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${my.log.dir}/test-servlet-logging-%d{yyyy-MM-dd}.ndjson</fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>500MB</totalSizeCap>
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <includeContext>false</includeContext>
            <includeMdc>true</includeMdc>
            <timestampPattern>uuuu-MM-dd'T'HH:mm:ss.SSSxxx</timestampPattern>
            <fieldNames>
                <timestamp>@timestamp</timestamp>
                <message>message</message>
                <thread>thread</thread>
                <logger>logger</logger>
                <level>level</level>
                <levelValue>[ignore]</levelValue>
                <version>[ignore]</version>
                <stackTrace>ex</stackTrace>
            </fieldNames>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
        <appender-ref ref="JSON-FILE" />
    </root>
</configuration>
Elaterin answered 31/3, 2022 at 14:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.