如何在 Spring Boot 中集成日志框架 SLF4J、Log4j

文章目录

笔者的操作环境:

  • Spring Cloud Alibaba:2022.0.0.0-RC2

  • Spring Cloud:2022.0.0

  • Spring Boot:3.0.2

  • Nacos 2.2.3

  • Maven 3.8.3

  • JDK 17.0.7

  • IntelliJ IDEA 2022.3.1 (Ultimate Edition)

具体步骤

  1. 因为 Spring Boot 已经内置了 Logback,所以需要先将 Logback 移除。移除的方法是在 Spring Boot 依赖包中移除 Logback。

    xml 复制代码
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>

    比如就像这样:

    xml 复制代码
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    【踩坑提醒】

    如何使用了 Maven 多模块,必须在所有依赖 Logback 的依赖包中将 Logback 排除,否则 Spring Boot 启动时会发生如下报错:

    txt 复制代码
    SLF4J: Class path contains multiple SLF4J providers.
    SLF4J: Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider@4f51b3e0]
    SLF4J: Found provider [org.apache.logging.slf4j.SLF4JServiceProvider@4b9e255]
    SLF4J: See https://www.slf4j.org/codes.html#multiple_bindings for an explanation.
    SLF4J: Actual provider is of type [ch.qos.logback.classic.spi.LogbackServiceProvider@4f51b3e0]

    比如,下面这两个 Spring Boot 依赖包中都依赖了 Logback,所以都要排除 Logback。

    xml 复制代码
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    xml 复制代码
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    如果想确定自己的 Maven 模块有没有依赖 Logback,可以在 IntelliJ IDEA 中查看。

    比方说,下面这种情况就属于同时依赖了 Logback、Log4j2,这样 Spring Boot 就会在启动时报错。


  2. 引入与 Spring Boot 适配的 Log4j2 依赖包。

    xml 复制代码
    <!-- 设置 SLF4J 与之绑定的日志包。无需提供 SLF4J 的 JAR 包,因为 Lombok 已经提供了 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
        <version>Spring Boot 的版本</version>
    </dependency>

    此依赖包的版本与 Spring Boot 是一致的。如果不清楚应该使用什么版本,可以去 Maven 仓库中查询。Maven 仓库官网:https://mvnrepository.com/


    【提示】

    对于不使用 Spring Boot 的项目,使用的是如下经典 Log4j2 依赖配置。使用 Spring Boot 之后,此依赖配置是多余的。

    xml 复制代码
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>Log4j2 的版本</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>Log4j2 的版本</version>
    </dependency>
    <!-- 设置 SLF4J 与之绑定的日志包。无需提供 SLF4J 的 JAR 包,因为 Lombok 已经提供了 -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>Log4j2 的版本</version>
    </dependency>

    读者可以自行检查,Spring Boot 适配的 Log4j2 依赖包已经包含了上述经典 Log4j2 依赖配置。


  3. 提供 Log4j2 的日志配置文件。

    如果不提供此配置,则 Spring Boot 会提供一个默认配置。通常,默认配置也不是很糟糕,但它有一个严重的问题,它不会将日志输出至文件来备份。因此,不能使用默认配置。

    一个示例的 Log4j2 的日志配置如下,读者可以自行变更为自己喜欢的配置。

    xml 复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    
    <configuration status="OFF">
        <Properties>
            <property name="console_log_pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [%level] [%t] %l %n %m%n</property>
            <property name="file_log_pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [%level] [%t] %C.%M[%L line] %n %m%n</property>
            <property name="every_file_size">20MB</property>
        </Properties>
    
        <appenders>
            <Console name="Console" target="SYSTEM_OUT">
                <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
                <PatternLayout pattern="${console_log_pattern}"/>
            </Console>
    
            <RollingFile name="DEBUG" fileName="./log/log4j2/debug.log"
                         filePattern="./log/log4j2/debug_log_archive/debug-%d{yyyy-MM-dd}-%i.log.zip">
                <PatternLayout pattern="${file_log_pattern}"/>
                <Policies>
                    <SizeBasedTriggeringPolicy size="${every_file_size}"/>
                </Policies>
                <Filters>
                    <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
                </Filters>
            </RollingFile>
    
            <RollingFile name="INFO" fileName="./log/log4j2/info.log"
                         filePattern="./log/log4j2/info_log_archive/info-%d{yyyy-MM-dd}-%i.log.zip">
                <PatternLayout pattern="${file_log_pattern}"/>
                <Policies>
                    <SizeBasedTriggeringPolicy size="${every_file_size}"/>
                </Policies>
                <Filters>
                    <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
                </Filters>
            </RollingFile>
    
            <RollingFile name="WARN" fileName="./log/log4j2/warn.log"
                         filePattern="./log/log4j2/warn_log_archive/warn-%d{yyyy-MM-dd}-%i.log.zip">
                <PatternLayout pattern="${file_log_pattern}"/>
                <Policies>
                    <SizeBasedTriggeringPolicy size="${every_file_size}"/>
                </Policies>
                <Filters>
                    <ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
                </Filters>
            </RollingFile>
    
            <RollingFile name="ERROR" fileName="./log/log4j2/error.log"
                         filePattern="./log/log4j2/error_log_archive/error-%d{yyyy-MM-dd}-%i.log.zip">
                <PatternLayout pattern="${file_log_pattern}"/>
                <Policies>
                    <SizeBasedTriggeringPolicy size="${every_file_size}"/>
                </Policies>
                <Filters>
                    <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
                </Filters>
            </RollingFile>
    
        </appenders>
    
        <loggers>
            <!-- 属性 level 是用于设置最低需要输出的日志输出级别 -->
            <root level="DEBUG">
                <appender-ref ref="Console"/>
                <appender-ref ref="DEBUG"/>
                <appender-ref ref="INFO"/>
                <appender-ref ref="WARN"/>
                <appender-ref ref="ERROR"/>
            </root>
        </loggers>
    </configuration>
  4. Log4j2 的日志配置文件编写完成之后,可以放在 Maven 模块的 resource 目录下,如下图所示。

    然后,在 Spring Boot 配置文件(如 application.yml)中使用如下代码引入该配置。

    yml 复制代码
    logging:
      config: classpath:log4j2.xml

    如果 Log4j2 的日志配置文件名为 log4j2.xmllog4j2-spring.xml,且放在 resource 目录下,那就算是不在 Spring Boot 配置文件中引入此 Log4j2 的日志配置,Spring Boot 也会自动读取该 Log4j2 的日志配置。不过,最好还是显式地引入此配置。


    【注意】

    如果使用了 Maven 多模块,则此 Log4j2 的日志配置文件和 Spring Boot 配置文件只能放在 Spring Boot 入口模块中。不要在一种没有程序启动入口的 Maven 库模块中放置此配置文件


  5. 前面已经导入了 Log4j2,现在来考虑 SLF4J。

    SLF4J 是一种门面日志,它只要发现导入了 Log4j2,它就会自动使用它。

    幸运的是,有一个众所周知的插件叫 Lombok,它已经内置了 SLF4J。因此只要使用 Lombok,就可以不需要引入 SLF4J 依赖。

  6. 引入 Lombok 的依赖代码如下。

    xml 复制代码
    <!-- 注意:Lombok 不会在依赖中被继承 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>Lombok 的版本</version>
        <scope>provided</scope>
    </dependency>
  7. 然后,在需要使用 SLF4J 的类上使用注解 @Slf4j。这样就可以直接在代码中使用 log.xxx(...) 来使用 Log4j2 日志了。

    java 复制代码
    @Slf4j
    public class UserAvatarController {
        // ...省略其它内容...
        public void fun(HttpServletRequest request, HttpServletResponse response) {
            log.info("fun called");
    }

附录

相关推荐
腥臭腐朽的日子熠熠生辉1 小时前
解决maven失效问题(现象:maven中只有jdk的工具包,没有springboot的包)
java·spring boot·maven
绝顶少年3 小时前
Spring Boot 注解:深度解析与应用场景
java·spring boot·后端
西木风落3 小时前
springboot整合Thymeleaf web开发出现Whitelabel Error Page
spring boot·thymeleaf error·whitelabelerror
有来技术5 小时前
从0到1手撸企业级权限系统:基于 youlai-boot(开源) + Java17 + Spring Boot 3 完整实战
java·spring boot·后端
橘猫云计算机设计5 小时前
基于springboot微信小程序的旅游攻略系统(源码+lw+部署文档+讲解),源码可白嫖!
java·spring boot·后端·微信小程序·毕业设计·旅游
风象南6 小时前
SpringBoot中6种跨域请求解决方案
java·spring boot·后端
良枫6 小时前
Spring Security认证授权深度解析
spring boot·spring
码视野6 小时前
基于SpringBoot的河道水情大数据可视化分析平台设计与实现(源码+论文+部署讲解等)
spring boot·后端·物联网·信息可视化·论文·本科毕业论文·计算机专业毕业论文
用键盘当武器的秋刀鱼7 小时前
springBoot统一响应类型3.5.3版本
java·spring boot·spring
喻米粒062211 小时前
RabbitMQ消息相关
java·jvm·spring boot·spring·spring cloud·sentinel·java-rabbitmq