日志框架配置和使用
功能描述
在 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 Demo 模块
包含 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 Demo 模块
Spring-boot 支持通过启动器引入 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 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 错误代码