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