日誌框架設定與使用
功能說明
在 dubbo 3.3.0-beta.3 之前,dubbo 和 dubbo-samples 使用 log4j 和 logback 的混合模式,由於部分模組缺少日誌配置,導致經常出現衝突和錯誤。因此,在 3.3.0-beta.3 之後,日誌元件已升級為 log4j2,以簡化操作並降低維護成本。本文檔說明如何配置和使用日誌框架,以避免因間接引入多個日誌框架而導致的衝突。
使用方法
使用慣例
- 請使用 log4j2 作為日誌框架,避免使用 log4j 和 logback。除了一些遺留場景外,使用單一日誌框架可以降低使用成本並防止衝突。
- 避免向上游傳遞日誌框架依賴項,這可以通過在 maven 中將 scope 設定為
test
或provider
,或設定<optional>true</optional>
來解決。作為一個服務框架,dubbo 理應避免傳遞非必要的依賴項,並將日誌框架的選擇權留給使用者。
使用場景
1. 一般 dubbo 模組
大多數模組屬於此類型,通常需要日誌框架進行單元測試。
包含 Maven 依賴項,注意如果父項已經包含,則無需再次新增
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <scope>test</scope> </dependency>
新增 log4j2 日誌配置
src/test/resources/log4j2-test.xml
,使用此名稱的原因是為了確保最高優先順序。<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT" follow="true"> <PatternLayout pattern="%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}" charset="UTF-8"/> </Console> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
2. 非 Spring Boot 範例模組
包含 Maven 依賴項,注意如果父項已經包含,則無需再次新增
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactI> </dependency>
新增 log4j2 日誌配置
src/test/resources/log4j2-test.xml
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT" follow="true"> <PatternLayout pattern="%style{%d{HH:mm:ss.SSS}}{Magenta} %style{|-}{White}%highlight{%-5p} [%t] %style{%40.40c}{Cyan}:%style{%-3L}{Blue} %style{-|}{White} %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect)}" disableAnsi="false" charset="UTF-8"/> </Console> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
3. Spring Boot 範例模組
Spring Boot 支援透過 starter 導入 log4j2 相依性,但請注意 Spring Boot 預設使用 Logback,因此需要在 <dependencyManagement>
中排除它。
排除 spring-boot-starter-logging
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>${spring-boot.version}</version> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </dependencyManagement>
加入 Maven 相依性
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency>
新增 log4j2 設定檔
src/main/resources/log4j2.xml
此步驟為選用,因為 Spring Boot 已內建預設的日誌設定。
4. Spring Boot 原生 Demo 模組
由於 log4j2 尚未支援原生編譯,請使用 Logback 作為日誌框架。無需進行任何變更,保留現有方法,並確保不要間接引入 log4j 或 slf4j-log4j12。
常見的日誌框架問題
1. 缺少日誌框架
主控台輸出
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See SLF4J Error Codes for further details.
解決方案:新增 log4j2 相依性
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactI>
</dependency>
2. 日誌框架衝突
主控台輸出
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:.../slf4j-log4j12-1.x.x.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:.../logback-classic-1.x.x.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:.../log4j-slf4j-impl-2.x.x.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]
或者
Exception in thread "main" java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath
解決方案:排除除了 log4j-slf4j-impl 以外的所有相關依賴性。強烈建議使用 Maven Helper - IntelliJ IDEs Plugin 來分析和排除依賴性。
3. 其他問題
參考:SLF4J 錯誤碼