日誌框架設定與使用

如何在 dubbo 和 dubbo-samples 中配置和使用日誌框架

功能說明

在 dubbo 3.3.0-beta.3 之前,dubbo 和 dubbo-samples 使用 log4j 和 logback 的混合模式,由於部分模組缺少日誌配置,導致經常出現衝突和錯誤。因此,在 3.3.0-beta.3 之後,日誌元件已升級為 log4j2,以簡化操作並降低維護成本。本文檔說明如何配置和使用日誌框架,以避免因間接引入多個日誌框架而導致的衝突。

使用方法

使用慣例

  • 請使用 log4j2 作為日誌框架,避免使用 log4j 和 logback。除了一些遺留場景外,使用單一日誌框架可以降低使用成本並防止衝突。
  • 避免向上游傳遞日誌框架依賴項,這可以通過在 maven 中將 scope 設定為 testprovider,或設定 <optional>true</optional> 來解決。作為一個服務框架,dubbo 理應避免傳遞非必要的依賴項,並將日誌框架的選擇權留給使用者。

使用場景

1. 一般 dubbo 模組

大多數模組屬於此類型,通常需要日誌框架進行單元測試。

  1. 包含 Maven 依賴項,注意如果父項已經包含,則無需再次新增

        <dependency>
          <groupId>org.apache.logging.log4j</groupId>
          <artifactId>log4j-slf4j-impl</artifactId>
          <scope>test</scope>
        </dependency>
    
  2. 新增 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 範例模組

  1. 包含 Maven 依賴項,注意如果父項已經包含,則無需再次新增

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactI>
        </dependency>
    
  2. 新增 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> 中排除它。

  1. 排除 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>
    
  2. 加入 Maven 相依性

        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
    
  3. 新增 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 錯誤碼