日志框架配置和使用

如何在 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 Demo 模块

  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 Demo 模块

Spring-boot 支持通过启动器引入 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 native Demo 模块

由于 log4j2 还不支持 native,因此使用 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 错误代码


上次修改时间:2023 年 12 月 14 日:添加统一使用 log4j2 作为日志的文档 (#2869) (6ba331b4e3b)