如何在 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");
    }

附录

相关推荐
m0_7482309429 分钟前
SpringBoot实战(三十二)集成 ofdrw,实现 PDF 和 OFD 的转换、SM2 签署OFD
spring boot·后端·pdf
不一样的信息安全3 小时前
Spring Boot框架下的上海特产销售商城网站开发之旅
网络·spring boot
lozhyf3 小时前
基于SpringBoot + Mybatis Plus + SaToken + Thymeleaf + Layui的后台管理系统
spring boot·layui·mybatis
乙卯年QAQ4 小时前
【Elasticsearch】Springboot编写Elasticsearch的RestAPI
spring boot·elasticsearch
生产队队长5 小时前
项目练习:若依后台管理系统-后端服务开发步骤(springboot单节点版本)
java·spring boot·后端
m0_748236835 小时前
【wiki知识库】08.添加用户登录功能--后端SpringBoot部分
java·spring boot·后端
小扳6 小时前
博客之星2024年度-技术总结:技术探险家小板的一年的征程
java·大数据·spring boot·elasticsearch·搜索引擎·spring cloud·微服务
m0_512744646 小时前
如何在idea中搭建SpringBoot项目
java·spring boot·intellij-idea
中國移动丶移不动7 小时前
分布式系统通信解决方案:Netty 与 Protobuf 高效应用
java·spring boot·后端
m0_748234088 小时前
Spring Boot 3.3.4 升级导致 Logback 之前回滚策略配置不兼容问题解决
java·spring boot·logback