2019-03-05 · Develop

ActiveMQ和Logback日志冲突问题解决

记录一次 ActiveMQ 和 Logback 冲突问题。

发现问题

最近一个老项目中日志混乱,想使用 logback 进行下日志管理引入如下的依赖

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.25</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>org.logback-extensions</groupId>
    <artifactId>logback-ext-spring</artifactId>
    <version>0.1.2</version>
    <exclusions>
        <exclusion>
            <artifactId>logback-classic</artifactId>
            <groupId>ch.qos.logback</groupId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jul-to-slf4j</artifactId>
    <version>1.7.25</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.25</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.25</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-to-slf4j</artifactId>
    <version>2.10.0</version>
</dependency>

添加日志配置文件 logback.xml

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="false" scanPeriod="60000" debug="false">
    <property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%15.15t] %-40.40logger{39}:%m%n"/>
    <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%t] %-40.40logger{39} : %m%n"/>
    <property name="LOG_FILE" value="${catalina.home}/logs/${hostname:-spring}.log"/>

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
        <file>${LOG_FILE}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
            <maxFileSize>${LOG_FILE_MAX_SIZE:-10MB}</maxFileSize>
            <maxHistory>${LOG_FILE_MAX_HISTORY:-0}</maxHistory>
        </rollingPolicy>
    </appender>

    <!--<logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/>-->
    <!--<logger name="org.apache.catalina.util.LifecycleBase" level="ERROR"/>-->
    <!--<logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/>-->
    <!--<logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN"/>-->
    <!--<logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN"/>-->
    <!--<logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR"/>-->
    <!--<logger name="org.hibernate.validator.internal.util.Version" level="WARN"/>-->

    <root level="DEBUG">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

都是 springboot 中的默认配置 org/springframework/boot/logging/logback/base.xml 中的内容

然后启动确出现如下的错误,并不能正常的输出日志

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/IdeaProjects/zhph_operation/target/app/WEB-INF/lib/activemq-all-5.11.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/IdeaProjects/zhph_operation/target/app/WEB-INF/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
05-Mar-2019 12:35:26.318 INFO [RMI TCP Connection(3)-127.0.0.1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

其中的错误信息以及说明 activemq-all 和 logback-classic 都有 org.slf4j.impl.StaticLoggerBinder 这个类导致冲突。从之前的文章Java 日志关系梳理中我们知道 slf4j-log4j12log4j-over-slf4j 不能同时存在。既然是 jar 冲突,首先想到的是使用 maven 的 exclusions 功能,将 pom.xml 作如下的修改

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-all</artifactId>
    <version>5.11.1</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>

重启项目后错误依旧存在,原来是因为 activemq-all 使用了 maven 插件 maven-shade-plugin 来构建项目,将所有的依赖都构建到 jar 中,导致 exclusions 功能无法使用。这样就只能将 activemq-all 拆分使用到什么 jar 就引入什么 jar 。查看官方文档 http://activemq.apache.org/version-5-initial-configuration.html 知道 activemq-all 是由如下的功能组建而成

activemq-all-required-jars

看各自的项目中使用到了哪些 jar 不同的项目各有不同,我的项目中修改成如下的依赖就可以正常的输出日志了

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-pool</artifactId>
    <version>5.11.1</version>
    <exclusions>
        <exclusion>
            <artifactId>slf4j-api</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-broker</artifactId>
    <version>5.11.1</version>
</dependency>
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-client</artifactId>
    <version>5.11.1</version>
    <exclusions>
        <exclusion>
            <artifactId>slf4j-api</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-spring</artifactId>
    <version>5.7.0</version>
    <exclusions>
        <exclusion>
            <artifactId>spring-test</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>slf4j-api</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-beans</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>activemq-pool</artifactId>
            <groupId>org.apache.activemq</groupId>
        </exclusion>
    </exclusions>
</dependency>