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

news2025/2/23 18:23:00

文章目录

  • 具体步骤
  • 附录

笔者的操作环境:

  • 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。

    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
    

    比如就像这样:

    <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 启动时会发生如下报错:

    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。

    <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>
    
    <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 依赖包。

    <!-- 设置 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 之后,此依赖配置是多余的。

    <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 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)中使用如下代码引入该配置。

    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 的依赖代码如下。

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

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

附录

  • Log4j2

    • Log4j2 的开源地址:https://github.com/apache/logging-log4j2

    • Log4j2 官方文档:https://logging.apache.org/log4j/2.x/manual/index.html

  • SLF4J

    • SLF4J 官网:https://www.slf4j.org/

    • SLF4J 官方文档:https://www.slf4j.org/docs.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/850998.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【BMC】OpenBMC开发基础2:修改原有程序

修改原有程序 通常情况下我们会需要修改OpenBMC原有的程序来适配我们的项目&#xff0c;本节将介绍一般的流程。 为此首先我们需要了解devtool这个工具&#xff0c;注意它不是前端开发用的那个devtool&#xff0c;而是由OE&#xff08;或者Yocto&#xff1f;&#xff09;提供…

当肠道免疫系统与微生物共舞:了解肠道免疫细胞和肠道菌群互作

谷禾健康 同样暴露在含有致病微生物的环境中&#xff0c;有的人很少生病&#xff0c;有的人却很容易感染并生病。这是因为每个人的机体对潜在的病原体产生的免疫应答不同。 ★ 固有免疫和适应性免疫保护着人体 人体的免疫应答分为固有免疫&#xff08;先天免疫&#xff09;和适…

AVS3:跨多通道预测PMC

前面的文章中介绍了TSCPM&#xff0c;它是AVS3中用于intra模式的跨通道预测技术&#xff0c;它利用线性模型根据亮度重建像素预测色度像素&#xff0c; 跨通道预测技术用于去除不同通道间的冗余信息&#xff0c;TSCPM可以去除Y-Cb、Y-Cr通道间的冗余&#xff0c;然而却忽略了…

# Failed to initialize NVML: Driver/library version mismatch 的解决方法

Failed to initialize NVML: Driver/library version mismatch 的解决方法 首发于知乎: https://zhuanlan.zhihu.com/p/643343668 全网同名, 欢迎大家关注我的知乎帐号! 经常电脑好好的, 昨天还可以训练, 第二天忽然驱动就掉了: 这个错误通常表示NVIDIA驱动程序和NVIDIA管理库…

Octave Conv

Octave ConvOctave Convolution 代码详解_octconv代码_zghydx1924的博客-CSDN博客 def forward(self, x):X_h, X_l xif self.stride 2:X_h, X_l self.h2g_pool(X_h), self.h2g_pool(X_l)X_h2l self.h2g_pool(X_h)# X_h2l指的是对输入进行下采样&#xff0c;下采样的方法时卷…

用python做一个小游戏代码,用python制作一个小游戏

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;如何用python编写一个简单的小游戏&#xff0c;用python做一个小游戏代码&#xff0c;今天让我们一起来看看吧&#xff01; 今天呢&#xff0c;给大家展示一下Python有趣的小地方&#xff0c;展示给大家看看&#xff0c…

Android复习(Android基础-四大组件)——Service与Activity通信

我们前面学会了启动和停止服务的方法&#xff0c;但是服务虽然是在活动里启动的&#xff0c;但是启动服务之后&#xff0c;活动与服务之间基本没什么关系了。正常情况&#xff0c;我们在Activity里调用startService()方法启动MyService这个服务&#xff0c;然后MyService的onCr…

Openlayers实战:利用turf获取两个多边形的交集、差集、并集

在数据统计方面,通常会涉及到图形间的交集、并集、差集等。在Openlayers的实战中,我们显示两个多边形的交集、并集、差集的表现。通过turf的方式,可以快速的实现我们的数据处理,具体的请参考源代码。 效果图 源代码 /* * @Author: 大剑师兰特(xiaozhuanlan),还是大剑师…

three.js的镜面反射

three.js做成这种镜面反射的效果。 那就要使用three自带的功能Reflector 1.引入 组件 import { Reflector } from ../../node_modules/three/examples/jsm/objects/Reflector.js; 2.创建反射投影的存在面 let reflectorGeometry new THREE.PlaneBufferGeometry(100, 100); 3…

Java经典面试题总结(一)

Java经典面试题总结&#xff08;一&#xff09; 题一&#xff1a;Java编译运行原理题二&#xff1a;JDK&#xff0c;JVM&#xff0c;JRE三者之间的关系题三&#xff1a;谈一下对冯诺依曼体系的了解题四&#xff1a;重载与重写的区别题五&#xff1a;拆箱装箱是指什么&#xff1…

Spring源码解析(八):bean后置处理器CommonAnnotationBeanPostProcessor

Spring源码系列文章 Spring源码解析(一)&#xff1a;环境搭建 Spring源码解析(二)&#xff1a;bean容器的创建、默认后置处理器、扫描包路径bean Spring源码解析(三)&#xff1a;bean容器的刷新 Spring源码解析(四)&#xff1a;单例bean的创建流程 Spring源码解析(五)&…

本地项目如何连接git远程仓库

在本地新建项目后&#xff0c;如何连接git远程仓库呢&#xff1f;步骤如下&#xff1a; 第一步&#xff0c; 首先我们在git上新建仓库&#xff0c;设置模板可勾选Readme文件。&#xff08;readme文件的创建是为了介绍所写代码的一些详细信息,为了之后更好的维护。&#xff09;…

记录问题: servlet获取项目包绝对路径

【2023-8-8 23:46:27 星期二】 如何获取在webapp下的路径?而不是target包下的webapp目录 比如这里应该获取到 F:\Tiam\Desktop\freemarker\freemarker-demo01\src\main\webapp 而readPath总是获取到 F:\Tiam\Desktop\freemarker\freemarker-demo01\target\freemarker-demo0…

Leetcode-每日一题【剑指 Offer 11. 旋转数组的最小数字】

题目 把一个数组最开始的若干个元素搬到数组的末尾&#xff0c;我们称之为数组的旋转。 给你一个可能存在 重复 元素值的数组 numbers &#xff0c;它原来是一个升序排列的数组&#xff0c;并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如&#xff0c;数组 [3,4…

Styletron: 面向组件的样式设计工具包

styletron官网&#xff1a; styletron的GitHub链接&#xff1a; styletron-react 一. 介绍 Styletron是一个通用的component-oriented&#xff08;面向组件的&#xff09;样式工具。它属于css-in-js类别。Styletron可以很好地与React配合使用&#xff0c;但也可以与其他框架或…

Allegro172版本无法低亮颜色的解决办法

Allegro172版本无法低亮颜色的解决办法 在用Allegro172版本做PCB设计的时候,高亮颜色是常用的命令,同时将高亮的颜色去高亮也是使用的十分频繁。 有时在去高亮的时候会出现无法去高亮的情况如下图 右边这块铜皮被高亮成了白色 可以看到即便使用去高亮命令,铜皮的颜色仍然还…

初次使用GPU云服务器

前言&#xff1a; 在体验了GPU云服务器&#xff08;GPU Cloud Computing&#xff0c;GPU&#xff09;后&#xff0c;我认为这是一个非常强大的弹性计算服务。它为深度学习、科学计算、图形可视化、视频处理等多种应用场景提供了强大的GPU算力&#xff0c;能够满足各类用户的计算…

web集群学习--基于CentOS构建LVS-DR集群、配置nginx负载均衡

基于CentOS构建LVS-DR集群 环境准备 主机名 ip地址 node1 192.168.1.140 client node2 192.168.1.141 LVS node3 192.168.1.142 RS1 node4 192.168.1.143 RS2配置 1.关闭防火墙和SELinux [rootclient~]# systemctl stop firewalld [rootclient~]# systemctl disabl…

实现UDP可靠性传输

文章目录 1、TCP协议介绍1.1、ARQ协议1.2、停等式1.3、回退n帧1.4、选择性重传 1、TCP协议介绍 TCP协议是基于IP协议&#xff0c;面向连接&#xff0c;可靠基于字节流的传输层协议 1、基于IP协议&#xff1a;TCP协议是基于IP协议之上传输的&#xff0c;TCP协议报文中的源端口IP…

【Linux升级之路】5_基础IO

&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f; &#x1f36d;&#x1f36d;系列专栏&#xff1a;【Linux升级之路】 ✒️✒️本篇内容&#xff1a;文件操作&#xff0c;文件管理&#xff0c;重定向&#xff0c;简易shell添加重定向功能&#xff0c;文件属…