9. Spring Boot 日志文件

news2024/12/23 15:08:09

本篇文章源码位置延续上个章节: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/logging
  level:
    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/logging
  level:
    root: debug
    com:
      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.log
  level:
    root: warn

application-dev.yml:

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

application-prod.yml:

logging:
  file:
    name: /Users/chenshu/Documents/logging/prod_logging.log
  level:
    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.coloradmin.cn/o/1597245.html

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

相关文章

学习经验分享【32】本科/硕士开题报告、中期报告等写作经验分享

本科/硕士阶段首先就是要写开题报告&#xff0c;然后中期报告&#xff0c;这篇博文就是分享一下写报告的经验&#xff0c;避免被老师打回来。本人有丰富的写报告经验&#xff0c;有需要的朋友可添加文末联系方式与我联系。 一、本科开题报告的提纲 课题来源及研究的目的和意义…

C++内存分布

C代码编译过程 预处理 宏定义展开、头文件展开、条件编译&#xff0c;这里并不会检查语法编译检查语法&#xff0c;将预处理后文件编译生成汇编文件汇编将汇编文件生成目标文件(二进制文件)链接将目标文件链接为可执行程序 进程的内存分布 程序运行起来(没有结束前)就是一个…

openjudge_2.5基本算法之搜索_166:The Castle

题目 166:The Castle 总时间限制: 1000ms 内存限制: 65536kB 描述 Figure 1 shows the map of a castle.Write a program that calculates how many rooms the castle hashow big the largest room is The castle is divided into m * n (m<50, n<50) square modules.…

如何应对Android面试官 -> startActivity 流程详解

前言 本章主要讲解下 Activity 的启动流程&#xff1b; 整体概念 点击桌面图标&#xff0c;启动目标应用程序的 Activity&#xff0c;首先会跟 AMS 打交道&#xff0c;也就是 SystemServer 进程中启动的AMS&#xff0c;Launcher 进程和 SystemServer 进程中的 AMS 通信「一次跨…

(九)C++自制植物大战僵尸游戏自定义对话框的实现

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/m0EtD 对话框在游戏的交互中非常重要。在游戏中&#xff0c;对话框不仅可以提醒用户下达任务指令&#xff0c;而且还可以让用户进行操作&#xff0c;自定义游戏中的各种属性。对话框在游戏的交互中非常常见且大量使用。Co…

树莓集团与天府新区信息职业学院在国际数字影像产业园成功举办授牌仪式

2024年4月12日&#xff0c;树莓集团与天府新区信息职业学院共同在国际数字影像产业园举办授牌仪式。这场仪式不仅标志着双方合作的正式开启&#xff0c;更是为未来的产教融合、学生实训与就业推荐树立了坚实的基石。 仪式上&#xff0c;天府新区信息职业学院领导与树莓集团的代…

Qt QStyle详解

1.简介 QStyle类是 Qt 框架中用于控制应用程序界面元素外观的一个抽象基类。这个类提供了一种方式来定制窗口部件&#xff08;widgets&#xff09;的绘制和行为&#xff0c;可以通过改变主题或风格来更改应用程序的外观&#xff0c;而无需修改窗口部件本身的代码。 Qt包含一组…

抽奖系统设计

如何设计一个百万级用户的抽奖系统&#xff1f; - 掘金 如何设计百万人抽奖系统…… 在实现抽奖逻辑时&#xff0c;Redis 提供了多种数据结构&#xff0c;选择哪种数据结构取决于具体的抽奖规则和需求。以下是一些常见场景下推荐使用的Redis数据结构&#xff1a; 无序且唯一奖…

系统边界图

系统边界图的定义&#xff1a; 系统边界图是系统工程和软件工程中的一种图形化工具&#xff0c;用于描述系统与外部世界之间的交互和界限。它展示了系统的组成部分以及这些组件如何与外部实体进行通信和交互。系统边界图通常包括系统内部的各个组件、外部实体以及它们之间的通信…

【Qt】:事件的处理

系统相关 一.鼠标事件二.键盘事件三.定时器 事件是应用程序内部或者外部产生的事情或者动作的统称。在Qt中使用一个对象来表示一个事件。所有的Qt事件均继承于抽象类QEvent。事件是由系统或者Qt平台本身在个同的的刻友出的。当用广投下鼠标、敲下键盘&#xff0c;或者是窗口需要…

掼蛋残局技巧

一、根据对手张数出牌 口诀&#xff1a;十打二来九打一&#xff0c;打成八张不着急&#xff1b; 对手七张或八张&#xff0c;可以反手打一夯&#xff1b; 五打二来六打三&#xff0c;打得对手把眼翻&#xff1b; 枪不打四&#xff1b; 两张&#xff1a;出两张以上的牌&#xff…

AI预测福彩3D第36弹【2024年4月15日预测--第8套算法开始计算第4次测试】

今天咱们继续测试第8套算法和模型&#xff0c;今天是第3次测试&#xff0c;目前的测试只是为了记录和验证&#xff0c;不建议大家盲目跟买。。我的目标仍旧是10次命中3-4次!~废话不多说了&#xff0c;直接上结果&#xff01; 2024年4月15日3D的七码预测结果如下 第一套…

【Leetcode每日一题】 动态规划 - 下降路径最小和(难度⭐⭐)(55)

1. 题目解析 题目链接&#xff1a;931. 下降路径最小和 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了. 2.算法原理 对于这类路径类问题&#xff0c;通常我们首先需要分析状态表示以及状态转移的过程。特别地&#xff0c;本题涉及…

虚良SEOPython脚本寄生虫程序源码

本程序&#xff0c;快速收录百度首页&#xff0c;3-5天就可以有流量&#xff0c;长期稳定&#xff0c;可以设置自动推送。 点这里 Python脚本寄生虫程序源码&#xff08;寄生虫电影脚本&#xff09; - 虚良SEO 模板可以自己修改&#xff0c;源码带模板标签说明&#xff0c;简…

106.从中序与后序遍历构造二叉树

给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 思路&#xff1a; 中序遍历数组中&#xff0c;找到一个根节点&#xff0c;那么其前为其左子树&a…

CameraCtrl、EDTalk、Sketch3D、Diffusion^2、FashionEngine

本文首发于公众号&#xff1a;机器感知 CameraCtrl、EDTalk、Sketch3D、Diffusion^2、FashionEngine NVINS: Robust Visual Inertial Navigation Fused with NeRF-augmented Camera Pose Regressor and Uncertainty Quantification In recent years, Neural Radiance Fields …

【团体程序设计天梯赛 往年关键真题 25分题合集 详细分析完整AC代码】(L2-001 - L2-024)搞懂了赛场上拿下就稳了

L2-001 紧急救援 最短路路径打印 样例 输入1 4 5 0 3 20 30 40 10 0 1 1 1 3 2 0 3 3 0 2 2 2 3 2输出1 2 60 0 1 3分析 用一遍dijkstra算法。设立 n u m [ i ] num[i] num[i]和 w [ i ] w[i] w[i]表示从出发点到i结点拥有的路的条数&#xff0c;以及能够找到的救援队的数目…

吴恩达llama课程笔记:第六课code llama编程

羊驼Llama是当前最流行的开源大模型&#xff0c;其卓越的性能和广泛的应用领域使其成为业界瞩目的焦点。作为一款由Meta AI发布的开放且高效的大型基础语言模型&#xff0c;Llama拥有7B、13B和70B&#xff08;700亿&#xff09;三种版本&#xff0c;满足不同场景和需求。 吴恩…

Avalonia中MVVM模式下设置TextBox焦点

Avalonia中MVVM模式下设置TextBox焦点 前言引入Nuget库程序里面引入相关库修改前端代码#效果图 前言 我们在开发的过程中,经常会遇到比如我在进入某个页面的时候我需要让输入焦点聚焦在指定的文本框上面,或者点击某个按钮触发某个选项的时候也要自动将输入焦点聚焦到指定的文…

Linux中断(栈、上下部)

进程线程中断的核心&#xff1a;栈 进程切换时&#xff0c;需要将当前进程的寄存器参数保存在当前进程的栈中。要再次执行此进程时需要先从栈中恢复此进程的寄存器参数。 对于同个进程的不同线程&#xff0c;代码和数据是所有线程共享的&#xff0c;所以线程间可以通过全局变量…