9. Spring Boot 日志文件

本篇文章源码位置延续上个章节:SpringBoot_demo

本篇文章内容源码位于上述地址的com/chenshu/springboot_demo/logging包下

1. 日志的作用

发现和定位问题: 日志是程序的重要组成部分,它在系统、程序出现错误或异常时提供诊断和解决问题的线索,从而定位问题;只有定位到了问题的位置,程序员才可以对症下药,从而解决问题。

除了发现和定位问题,我们还可以通过日志实现其他功能,比如:

  • 记录用户登录日志,用于分析用户是正常登录还是恶意破解登录;
  • 记录系统的操作日志,方便回复数据和定位操作人;

2. Spring Boot 日志概述

其实所谓日志我们也不是第一次接触了,在Spring Boot这个框架中集成了日志框架,我们在启动项目时在console中所打印的信息其实就是日志。

并且每一条日志记录都默认包含了这些信息:日志打印时间、日志打印级别、线程ID、线程名称、打印日志的类名、日志信息

image.png

以上内容就是Spring Boot 输出的控制台日志信息。

通过上述日志信息我们能引出下面几个问题:

  1. Spring Boot是因为内置了日志框架才能打印日志信息的,那么Spring Boot 内置的日志框架是什么呢?
  2. 打印日志是需要开销的,程序在不同的环境需要打印不同级别的日志信息,如何通过日志的级别来筛选所需打印日志的内容呢?
  3. 除了发现和定位问题,我们还想通过日志实现其他功能,那么开发者如何在程序中自定义打印日志呢?
  4. 开发环境中我们可以根据控制台打印的日志信息排查问题,那如果是生产环境总不能24小时盯着控制台信息找问题吧,这时候我们就要讲日志信息持久化保存,那么如何将日志信息持久化保存呢?

我们接下来要讲的内容就是针对上述问题。

3. Spring Boot 的内置日志框架【了解】

Spring Boot中内置的日志门面是SLF4J,而具体的日志实现是logback,日志门面是什么?日志实现又是什么?下面给大家简单说说。

3.1 门面模式

门面模式的核心为: 外部与一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用。

解释: 其实门面模式就相当于给各式各样的实现封装了一层统一的外观,对于用户来说不用关心市面上提供的各种各样的具体实现的api是什么,只需要通过门面所提供的统一的api来使用。

3.2 日志实现

市面上有许多日志实现,如:

  • Java原生的JUL(Java Util Logging)
  • log4j 1/2
  • logback

不同的日志实现,它们的api写法都有所不同,但凡你想去更改一种日志实现,都需要去更改每一处日志代码。

3.3 日志门面(Logging Facade)

为了解决上述问题,引入了日志门面,而SLF4j就是一种日志门面,通过SLF4J,我们可以随意换另外一个日志框架,应用程序不需要修改任意一行代码,就可以直接上线。

门面模式下的用户视角图示:

Untitled Diagram.drawio-4.png

4. 自定义日志打印

自定义打印日志的步骤大概分为下面两步:

  • 在程序中得到日志对象;
  • 使用日志相关语法输出要打印的内容;

4.1 得到日志对象

由于Spring Boot中内置的是slf4j的框架,这里我们要选择用org.slf4j包下的Logger接口:

image.png

使用LoggerFactory中的getLogger()方法,需要传一个参数来指定打印日志的类:

private static Logger log = LoggerFactory.getLogger(TestController.class);

4.2 通过日志对象打印信息

LoggingController里创建一个日志的测试方法,通过日志对象来调用方法,方法名称代表了日志级别,日志级别及使用会在后面说到。

image.png

这里我们使用info方法来测试:

@RestController
public class LoggingController {private static Logger log = LoggerFactory.getLogger(LoggingController.class);@RequestMapping("loggingtest1")public void loggingTest1() {log.info("This is my first Spring Boot Log.");}
}

成功打印出下面日志信息:

2024-04-07 21:23:34.681  INFO 14515 --- [nio-8001-exec-1] c.c.s.config.controller.TestController   : This is my first Spring Boot Log.

5. 日志持久化

a) 通过日志的保存名称持久化

在application.yml中通过配置日志的名称完成持久化:

# 日志的保存名称
logging:file:name: logging_demo.log

只设置名称会将日志默认保存在工作目录下:

image.png

点开查看一下:

image.png

还可以设置在指定路径下:

logging:file:name: /Users/chenshu/Documents/logging/logging_demo.log

b) 通过日志的保存目录持久化

在application.yml中通过配置日志的名称完成持久化:

# 日志的保存路径
logging:file:path: /Users/chenshu/Documents/logging

这样的设置会将日志保存在指定的路径下:

image.png

特性:

  1. 日志不会随着项目重新启动而去覆盖,会一直追加
  2. 当日志比较大的时候,会自动分割成多个文件,名称为原文件名+日期+.gz

6. 日志级别

不同的开发环境需要不同的日志级别

  • 测试环境下,我们不怎么考虑系统的开销,而是想要看到更多的日志信息,这时候我们就可以用开销来换取更多日志信息;
  • 开发环境下,我们也不怎么需要考虑系统的开销,但又想过滤掉一些不怎么需要的信息,以免影响查看日志;
  • 生产环境下,产品是要交付给用户进行使用的,使用的时候需要更多的考虑系统的开销,这时我们就可以只筛选一些重要的日志信息来节省开销;

6.1 六种日志级别

日志级别从低到高分别为:trace、debug、info、warn、error、fatal

  • trace: 追溯的意思,级别最低;
  • debug:需要调试时候的关键信息打印;
  • info:普通的打印信息(默认级别);
  • warn:警告,不影响程序运行,但需要注意的问题;
  • error:错误信息,级别较高的错误日志信息;
  • fatal:致命的,因为代码异常导致程序退出执行的事件;

由于fatal只会打印代码异常导致程序退出执行的事件,所以Logger对象提供了除了fatal事件的对应api:

@RequestMapping("loggingtest2")
public void loggingTest2() {//追溯log.trace("log level: trace");//调试log.debug("log level: debug");//信息log.info("log level: info");//警告log.warn("log level: warn");//错误log.error("log level: error");
}

访问对应路由后,发现控制台只打印了info、warn、error的日志:

2024-04-07 23:22:21.124  INFO 14925 --- [nio-8001-exec-1] c.c.s.logging.LoggingController          : log level: info
2024-04-07 23:22:21.124  WARN 14925 --- [nio-8001-exec-1] c.c.s.logging.LoggingController          : log level: warn
2024-04-07 23:22:21.124 ERROR 14925 --- [nio-8001-exec-1] c.c.s.logging.LoggingController          : log level: error

这是因为Spring Boot的日志级别默认是info,因此只会显示trace及以上的信息,接下来我来演示一下如何在不同环境的配置文件中设置不同的日志默认级别。

6.2 设置日志级别

日志级别的配置只需要在配置文件中设置"logging.level"配置项即可,我在前面配置的基础上进行修改:

logging:file:path: /Users/chenshu/Documents/logginglevel:root: debug

上面的root表示的是根路径,也就是所有信息的级别都为debug

重新访问路由方法后,打印了下面信息,证明我们确实把默认级别设置为debug

2024-04-07 23:56:38.246 DEBUG 15035 --- [nio-8001-exec-1] c.c.s.logging.LoggingController          : log level: debug
2024-04-07 23:56:38.246  INFO 15035 --- [nio-8001-exec-1] c.c.s.logging.LoggingController          : log level: info
2024-04-07 23:56:38.246  WARN 15035 --- [nio-8001-exec-1] c.c.s.logging.LoggingController          : log level: warn
2024-04-07 23:56:38.246 ERROR 15035 --- [nio-8001-exec-1] c.c.s.logging.LoggingController          : log level: error

上面那样配置会打印所有类中的debug及以上级别的日志信息,看起来非常眼花缭乱:

image.png


更精细化的日志级别设置

除了root根路径级别的设置,我们还可以精细化到自己的某个包中的级别,像下面这样,将com/chenshu/springboot_demo包下的类级别设置为debug,其他的类中的信息全都设置为warn:

logging:file:path: /Users/chenshu/Documents/logginglevel:root: debugcom:chenshu:springboot_demo: warn

这样的一番操作,相当于给com/chenshu/springboot_demo包下的类开了一个白名单,原先的一堆系统的日志信息都被过滤掉了,只剩下了我需要的重要日志信息:

2024-04-08 00:07:01.232  INFO 15095 --- [           main] c.c.s.SpringBootDemoApplication          : Starting SpringBootDemoApplication using Java 1.8.0_381 on chenshudeAir with PID 15095 (/Users/chenshu/Code/classcode_java/blog-demo/SpringBoot_demo/target/classes started by chenshu in /Users/chenshu/Code/classcode_java/blog-demo/SpringBoot_demo)
2024-04-08 00:07:01.234 DEBUG 15095 --- [           main] c.c.s.SpringBootDemoApplication          : Running with Spring Boot v2.7.6, Spring v5.3.24
2024-04-08 00:07:01.234  INFO 15095 --- [           main] c.c.s.SpringBootDemoApplication          : The following 1 profile is active: "dev"
2024-04-08 00:07:02.264  INFO 15095 --- [           main] c.c.s.SpringBootDemoApplication          : Started SpringBootDemoApplication in 1.353 seconds (JVM running for 1.892)
2024-04-08 00:07:23.780 DEBUG 15095 --- [nio-8001-exec-1] c.c.s.logging.LoggingController          : log level: debug
2024-04-08 00:07:23.780  INFO 15095 --- [nio-8001-exec-1] c.c.s.logging.LoggingController          : log level: info
2024-04-08 00:07:23.780  WARN 15095 --- [nio-8001-exec-1] c.c.s.logging.LoggingController          : log level: warn
2024-04-08 00:07:23.780 ERROR 15095 --- [nio-8001-exec-1] c.c.s.logging.LoggingController          : log level: error

6.3 不同生产环境的日志级别设置

对多环境配置文件设置不熟悉的小伙伴可以点击这里:多环境的配置文件设置

需求:将测试环境、开发环境、生产环境的日志分别存储在同一个目录下但命名不同的三个文件中,并且设置测试环境中的日志级别为trace、开发环境中为debug、生产环境中为warn

application-test.yml:

logging:file:name: /Users/chenshu/Documents/logging/prod_logging.loglevel:root: warn

application-dev.yml:

logging:file:name: /Users/chenshu/Documents/logging/dev_logging.loglevel:root: debug

application-prod.yml:

logging:file:name: /Users/chenshu/Documents/logging/prod_logging.loglevel:root: warn

在上述三个环境的配置文件中添加了日志打印级别以及持久化路径后,在主配置文件application.yml中分别设置spring.profiles.activetest、dev、prod,并启动项目。

application.yml:

# 运行环境设置
spring:profiles:active: test

分别运行后发现,指定路径确实出现了三个日志文件,并且由于test环境中的日志级别最低,因此文件最大;其次是dev环境;由于没有打印warn级别以上的日志信息,因此prod环境的日志为0bytes

image.png

7. 更简单的得到日志对象 —— lombok

7.1 通过lombok得到日志对象

上一篇文章提到过lombok的作用是利用注解来省略Java中冗余的代码,先前我们就使用过了@Data注解省略model对象的getter()、setter()、toString()等方法,此处我们也可以通过lombok更简单地得到日志对象

在启动项目前我就已经添加了lombok框架的依赖:

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>

导入相应的注解import lombok.extern.slf4j.Slf4j,在需要使用日志对象的类上添加@Slf4j的注解:

@RestController
@Slf4j
public class LoggingController {

添加此注解后,就相当于在类中添加了下面的代码(同4.1):

private static Logger log = LoggerFactory.getLogger(TestController.class);

在需要使用日志对象的时候,直接使用名为log的对象即可:

@RestController
@Slf4j
public class LoggingController {//private static Logger log = LoggerFactory.getLogger(LoggingController.class);@RequestMapping("loggingtest1")public void loggingTest1() {log.info("This is my first Spring Boot Log.");}@RequestMapping("loggingtest2")public void loggingTest2() {//追溯log.trace("log level: trace");//调试log.debug("log level: debug");//信息log.info("log level: info");//警告log.warn("log level: warn");//错误log.error("log level: error");}
}

7.2 lombok 原理解释

项目的target目录下的classes文件夹中存放了类编译后的字节码文件,找到相应目录下的字节码文件:SpringBoot_demo/target/classes/com/chenshu/springboot_demo/logging/LoggingController.class

image.png

把它拉到IDEA中打开查看字节码文件,发现直接把@Lombok注解转化为private static final Logger log = LoggerFactory.getLogger(LoggingController.class);

@RestController
public class LoggingController {private static final Logger log = LoggerFactory.getLogger(LoggingController.class);public LoggingController() {}@RequestMapping({"loggingtest1"})public void loggingTest1() {log.info("This is my first Spring Boot Log.");}@RequestMapping({"loggingtest2"})public void loggingTest2() {log.trace("log level: trace");log.debug("log level: debug");log.info("log level: info");log.warn("log level: warn");log.error("log level: error");}
}

也就是说lombok的注解是在编译之前转化为java代码,然后被编译为.class字节码文件:

Untitled Diagram.drawio.png

7.3 lombok 更多注解说明

注解作用
@Getter修饰类,自动添加 getter 方法
@Setter修饰类,自动添加 setter 方法
@ToString修饰类,自动添加 toString 方法
@EqualAndHashCode修饰类,自动添加 equals 和 hashcode 方法
@NoArgsConstructor修饰类,自动添加无参构造方法
@AllArgsConstructor修饰类,自动添加全属性构造方法,顺序按照属性定义的顺序
@NonNull修饰属性,属性不能为NULL
@RequiredArgsConstructor修饰类,自动添加所有final或@NonNull修饰过的属性作为参数的构造方法
@Data@Getter、@Setter、@ToString、@EqualsAndHashCode 和 @RequiredArgsConstructor 注解的组合

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

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

相关文章

深度探索:Secure Hash Algorithm(SHA)全景解析

title: 深度探索&#xff1a;Secure Hash Algorithm&#xff08;SHA&#xff09;全景解析 date: 2024/4/15 18:33:17 updated: 2024/4/15 18:33:17 tags: SHA安全抗碰撞性算法版本实现细节性能优化发展历史应用案例 密码学中的哈希函数 一、哈希函数的定义 哈希函数是一种数…

外卖点餐APP开发需要哪些功能

uni-app框架&#xff1a;使用Vue.js开发跨平台应用的前端框架&#xff0c;编写一套代码&#xff0c;可编译到Android、小程序等平台。 框架支持:springboot/Ssm/thinkphp/django/flask/express均支持 前端开发:vue.js 可选语言&#xff1a;pythonjavanode.jsphp均支持 运行软件…

SCI 四区(JEI)投稿到录用过程中的经历和心得体会

计算机视觉领域中&#xff0c;包含目标检测、三维重建、语义分割、图像分类等分支。其中&#xff0c;目标检测分支最卷&#xff0c;你知道的&#xff0c;没有背景和资源&#xff0c;发一篇SCI属实不易。本篇博客详细介绍本人投稿到录用过程中的经历和心得。 目录 1. 硬件资源落…

Vitis HLS 学习笔记--优化循环启动间隔(II)

目录 1. 概述 2. 常规矩阵乘法 3. 数据依赖性和内存访问模式 4. 优化循环 5. 总结 1. 概述 Initiation Interval&#xff08;II&#xff09;定义为启动连续操作之间的时间间隔&#xff0c;以时钟周期为单位。低的II是高性能和高资源利用率的关键。 较高的II意味着在单位…

使用DockerCompose配置基于哨兵模式的redis主从架构集群

文章目录 一、注意事项&#xff08;坑点&#xff01;&#xff01;&#xff01;&#xff09;二、配置Redis主从架构集群第一步&#xff1a;创建目录文件结构第二步&#xff1a;编写DockerCompose配置文件第三步&#xff1a;编写redis.conf第四步&#xff1a;启动redis主从集群 三…

CentOS如何使用Docker部署Plik服务并实现公网访问本地设备上传下载文件

文章目录 1. Docker部署Plik2. 本地访问Plik3. Linux安装Cpolar4. 配置Plik公网地址5. 远程访问Plik6. 固定Plik公网地址7. 固定地址访问Plik 本文介绍如何使用Linux docker方式快速安装Plik并且结合Cpolar内网穿透工具实现远程访问&#xff0c;实现随时随地在任意设备上传或者…

C语言 递归

递归指的是在函数的定义中使用函数自身的方法。 举个例子&#xff1a; 从前有座山&#xff0c;山里有座庙&#xff0c;庙里有个老和尚&#xff0c;正在给小和尚讲故事呢&#xff01;故事是什么呢&#xff1f;“从前有座山&#xff0c;山里有座庙&#xff0c;庙里有个老和尚&…

蓝桥杯-阿坤老师的魔方挑战

图示: 代码: #include <iostream> using namespace std; int main() {int N,i,j,row,col,sum,max0;cin>>N;int ar[N][N];for(i0;i<N;i){for(j0;j<N;j){cin>>ar[i][j];}//输入矩阵 }for(i0;i<N;i){row0;coli;sum0;//重新初始化while(row<N){if(c…

初识集合框架

前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; hellohello~&#xff0c;大家好&#x1f495;&#x1f495;&#xff0c;这里是E绵绵呀✋✋ &#xff0c;如果觉得这篇文章还不错的话还请点赞❤️❤️收藏&#x1f49e; &#x1f49e; 关注&#x1f4a5;&#x1f…

eclipse导入maven项目与配置使用本地仓库

前言 本人润国外了&#xff0c;发现不能用收费软件IDEA了&#xff0c;需要使用eclipse&#xff0c;这个免费。 但是早忘了怎么用了&#xff0c;在此总结下。 一、eclipse导入本地项目 1.选这个&#xff1a;open projects from file system… 2.找到项目文件夹&#xff0c;…

借力社交裂变,Xinstall助你实现用户快速增长

在数字化时代&#xff0c;社交裂变已成为品牌获取新用户、扩大影响力的关键手段。然而&#xff0c;如何有效利用社交裂变&#xff0c;实现用户快速增长&#xff0c;却是许多品牌面临的挑战。今天&#xff0c;我们将为大家介绍一个强大的社交裂变引擎——Xinstall&#xff0c;它…

Python中sort()函数、sorted()函数的用法深入讲解(具体实例:蓝桥杯数位排序)

前置知识&#xff1a; 可迭代对象的定义&#xff1a;可迭代对象是指可以被迭代或遍历的对象&#xff0c;即可以使用循环结构对其进行逐个访问的对象。 在Python中常见的可迭代对象有&#xff1a;列表(list)、元组&#xff08;tuple&#xff09;、字符串&#xff08;sting&…

基于SpringBoot+Vue实现的医院在线挂号系统(代码+万字文档)

系统介绍 基于SpringBootVue实现的医院在线挂号系统设计了三种角色&#xff0c;分别是管理员、医生、用户&#xff0c;每种角色对应不同的菜单 系统实现了个人信息管理、基础数据管理、论坛管理、用户管理、单页数据管理、医生管理及轮播图管理等功能模块&#xff0c;具体功能…

【大语言模型】基础:如何处理文章,向量化与BoW

词袋模型&#xff08;BoW&#xff09;是自然语言处理&#xff08;NLP&#xff09;和机器学习中一种简单而广泛使用的文本表示方法。它将文本文档转换为数值特征向量&#xff0c;使得可以对文本数据执行数学和统计操作。词袋模型将文本视为无序的单词集合&#xff08;或“袋”&a…

React 集成三方登录按钮样式的插件库

按钮不提供任何社交逻辑。 效果如下&#xff1a; 原地址&#xff1a;https://www.npmjs.com/package/react-social-login-buttons 时小记&#xff0c;终有成。

【C++成长记】C++入门 | 类和对象(中) |拷贝构造函数、赋值运算符重载、const成员函数、 取地址及const取地址操作符重载

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;C❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、拷贝构造函数 1、概念 2、特征 二、赋值运算符重载 1、运算符重载 2、赋值运算符重载 3、前置…

G2D图像处理硬件调用和测试-基于米尔-全志T113-i开发板

本篇测评由电子工程世界的优秀测评者“jf_99374259”提供。 本文将介绍基于米尔电子MYD-YT113i开发板的G2D图像处理硬件调用和测试。 MYC-YT113i核心板及开发板 真正的国产核心板&#xff0c;100%国产物料认证 国产T113-i处理器配备2*Cortex-A71.2GHz &#xff0c;RISC-V 外置…

SpringBoot启动流程分析之准备应用上下文refreshContext()

文章目录 源码入口1、准备刷新1.1、子类prepareRefresh()方法1.2 父类prepareRefresh&#xff08;&#xff09;方法 2、通知子类刷新内部bean工厂3、准备bean工厂4、允许上下文子类对bean工厂进行后置处理 源码入口 org.springframework.boot.SpringApplication#run(java.lang…

若依vue中关于字典的使用

文章目录 字典管理页面列表点击某个字典类型展示具体字典数据修改某一条字典数据 字典的应用一般用于select多选框中代码实现根据字典Dict的value获取Label&#xff0c;类似于通过key获得value 源码解析 字典管理页面 列表 点击某个字典类型展示具体字典数据 修改某一条字典数…

Zookeeper集群+消息队列Kafka

一. Zookeeper 集群的相关知识 1. zookeeper的概念 ZooKeeper 是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是Google的Chubby一个开源的实现&#xff0c;是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件&#xff0c;提供的…