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

simont
  • 68,704
  • 18
  • 117
  • 136
Soumya
  • 1,054
  • 2
  • 16
  • 31
  • 1
    Are you having `logback*.jar` in both `/lib` directory and in EAR/WAR? – Tomasz Nurkiewicz Mar 01 '12 at 15:16
  • 1
    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. – Soumya Mar 01 '12 at 15:45

4 Answers4

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>
James R. Perkins
  • 16,800
  • 44
  • 60
  • 1
    Workd a treat! Thanks. I guess we can exclude any module that we don't want using this file. Thanks again – Soumya Mar 01 '12 at 17:22
  • @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? – Zaw Than oo Mar 12 '14 at 09:08
  • @CycDemo it should work. If not something could be leaking out if your getting ClassCastException. What version of JBoss AS 7? – James R. Perkins Mar 12 '14 at 16:05
  • @James R. Perkins, I use JBoss AS 7.1.1 Final – Zaw Than oo Mar 12 '14 at 16:36
  • Not sure what it could be then. I know that others are successfully doing this. Maybe post a new question on the forums, https://community.jboss.org/en/jbossas7/content, or here with more details. – James R. Perkins Mar 13 '14 at 15:45
  • 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(); – Hassan Nov 04 '15 at 06:30
  • Where did you put the `jboss-deployment-structure.xml` in your deployment. – James R. Perkins Nov 04 '15 at 18:47
  • @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? – Vahid May 16 '17 at 15:55
  • 1
    For an EAR it needs to be in the `EAR/META-INF` directory and [each subdeployment where the exclusion](https://docs.jboss.org/author/display/WFLY10/Class+Loading+in+WildFly#ClassLoadinginWildFly-JBossDeploymentStructureFile) is required needs to be defined. For WIldFly 10 have a look at the [`add-logging-api-dependencies`](https://docs.jboss.org/author/display/WFLY10/Logging+Configuration#LoggingConfiguration-%7B%7Baddloggingapidependencies%7D%7D) attribute as well. – James R. Perkins May 16 '17 at 17:09
  • Excluding individual modules didn't work for me. Instead, I excluded the logging subsystem and that resolved my issue. – Vahid May 16 '17 at 19:46
  • 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.. – Phate Jul 23 '18 at 17:44
  • That seems odd. Are you including logback in your deployment? – James R. Perkins Jul 23 '18 at 19:01
  • @JamesR.Perkins How can I do the same trick with JBoss [The Oracle] 5.1.0.GA? I try to deploy jar file. – BarbosSergos Jul 03 '19 at 12:27
  • I'm not too sure. I'm not familiar with that version of JBoss. – James R. Perkins Jul 08 '19 at 20:24
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" />
osundblad
  • 2,675
  • 1
  • 29
  • 34
Torsten Krah
  • 368
  • 3
  • 9
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://stackoverflow.com/a/19695680/2587343

Community
  • 1
  • 1
Vlastimil Ovčáčík
  • 2,799
  • 27
  • 29
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>
gavenkoa
  • 45,285
  • 19
  • 251
  • 303