SpringBoot整合Slf4j、Logback、Log4j笔记


最近项目中整合Log4j的时候,始终是解决不了。问题的表象如下:

1. log4j.properties已经做了屏蔽控制台的输出,在本地时,Log4j日志文件确实没有再打印到了控制台了,但是发布到服务器上面时依旧会打印到控制台上面,如此,日志重定向加上本来就输出出来的log文件,导致最终采集到了双份的日志,做了大量的没有必要的工作。

2. log4j本身的日志文件project.log、SpringBoot使用Slf4j + Logback打印出来的spring.log整合不到一个文件里面去。

3. 根据网上的博客,专门配置了logback.xml文件,依旧没有彻底的解决log4j日志整合到slf4j体系中去。

最终通过了下面的步骤解决了,今天通过博客记录下大体的过程,以供后续参考。

 

1. 解决外挂log4j.properties不生效的作用。

  因为本地的log4j.properties是在项目内部的,而在服务器Tomcat中,配置文件是外挂在shared.loader=${catalina.base}/shared/config目录下的。检查服务器日志发现,我们引用的一个三方库(项目组已有源码)内包含了log4j.properties,导致每次启动的时候,先加载了jar包中的配置文件,而不是我们外挂配置出来配置文件。

 

  通过查看Log4j的源码得知,LogManager类110行使用到了Loader.getResource()方法来加载配置文件,继续想下看,发现它的加载顺序如下:

  1. Trying to find [" + resource + "] using context classloader " + classLoader + "."       本工程中的配置文件

  2. Trying to find [" + resource + "] using " + classLoader + " class loader.          项目jar包中的配置文件

  3. Trying to find [" + resource + "] using ClassLoader.getSystemResource().      系统类路径的配置文件

  搞清楚这个问题的所在之后,我们将三方库的log4j配置文件去掉后,重新打包引入。重新启动项目,可以加载到我们自定义出来的log4j配置文件,问题解决。

 

2. 第2个问题和第3个问题,实质上是一个问题,就是为什么在spring-boot-starter-logging中引入了slf4j到log4j的桥接包,我自己也写了简单的demo,里面都可以直接打印log4j日志。但是为什么没有在这个项目中就加载到和使用到。

  打印Gradle的依赖树 gradle dependencies 查到,项目中log4j相关的jar包一共引入了2个。一个是通过jxl导入的log4j.jar,另一个则是通过spring-boot-starter-logging导入的log4j-over-slf4j.jar桥包。两个jar包的package都是一模一样的。所以出现了类加载的冲突。查了类加载的资料以及slf4j的手册,得到如下结论:

  1. 由ClassLoader的双亲委托模式加载机制我们可以知道,假设两个包名和类名完全相同的class文件不再同一个jar包,如果一个class文件已经被加载java虚拟机里了,那么后面的相同的class文件就不会被加载了。

  2. Slf4j的手册中,也明确写了引入log4j-over-slf4j的第一步就是使用其覆盖原有的log4j.jar。

To use log4j-over-slf4j in your own application, the first step is to locate and then to replace log4j.jar with log4j-over-slf4j.jar. Note that you still need an SLF4J binding and its dependencies for log4j-over-slf4j to work properly.

  

  exclude掉jxl中的log4j.jar后,重新启动项目,log4j的日志输出已经到了slf4j的日志中了。问题已解决了一大半,剩下的就是修改自定义的logback配置文件。

 

3. 附一份自定义的logback.xml配置文件

  在application.properties中配置logging.config=classpath:logback-spring-${spring.profiles.active}.xml,其他配置文件如下:

文件:console-appender.xml

<?xml version="1.0" encoding="UTF-8"?>
<included>

    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!--encoder 默认配置为PatternLayoutEncoder-->
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
    </appender>

</included>

 

文件:file-appender.xml

<?xml version="1.0" encoding="UTF-8"?>
<included>

    <property name="LOG_ABSOLUTE_PATH" value="/applog/project.log" />

    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <!-- 日志记录器,日期滚动记录 -->
    <appender name="FILEOUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${LOG_ABSOLUTE_PATH}</file>
        <!-- 日志记录器的滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>${LOG_ABSOLUTE_PATH}.%i</fileNamePattern>
            <minIndex>1</minIndex>
            <maxIndex>10</maxIndex>
        </rollingPolicy>
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>100MB</maxFileSize>
        </triggeringPolicy>
        <!-- 追加方式记录日志 -->
        <append>true</append>
        <!-- 日志文件的格式 -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
    </appender>

</included>

 

文件:logback-spring-develop.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <contextName>my-project</contextName>

    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />

    <include resource="file-appender.xml" />

    <!-- 生产环境下,将此级别配置为适合的级别,以免日志文件太多或影响程序性能 -->
    <root level="INFO">
        <appender-ref ref="FILEOUT" />
    </root>
</configuration>

 

文件:logback-spring-local.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <contextName>my-project</contextName>

    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />

    <include resource="file-appender.xml" />
    <include resource="console-appender.xml" />

    <!-- 生产环境下,将此级别配置为适合的级别,以免日志文件太多或影响程序性能 -->
    <root level="INFO">
        <appender-ref ref="FILEOUT" />
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

 

4. 总结:

在《阿里巴巴Java开发手册(正式版)》中,日志规约一项第一条就强制要求使用SLF4J,如此可以很容易的从一个日志框架迁移到另一个日志框架上去。

【强制】应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架SLF4J中的API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

 

参考资料:

1. Tomcat中class和jar的加载顺序(转)

2. Apache Log4j源码

3. log4j-over-slf4j


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM