Spring Boot 日志文件

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Spring Boot 日志文件

引言



关于日志


我们日常在写代码的时候,出现了异常,都会在编译器的控制台上,找出问题。这些问题并不是我们盲猜的,而是控制台上有明显的日志打印,我们就可以根据日志打印发现问题、解决问题。所以说,日志是调试程序重要的一环。


此外,日志除了发现和定位问题外,它还有如下实用的功能:


  • 记录用户登录日志, 方便分析用户是正常登录还是恶意破解用户。
  • 记录系统的操作日志,方便数据恢复和定位操作人。
  • 记录程序的执行时间, 方便为以后优化程序提供数据支持。


基于上面的介绍,本篇博客着重介绍 Spring Boot 提供的日志框架。


一、Spring Boot 日志的格式说明



通常来说,如果我们的 Sping Boot 项目没有出现异常或错误信息,那么当我们运行启动类后,就会出现下面的日志信息:一个 Spring 图标,和一些基本都是 info 级别的日志信息。所以在一般情况下,我们就是通过这样的打印日志,来判定一个项目是否真正的编译无误了。


0252d220885b437a80c0619f0748c5b2.png


那么,这些日志信息是什么意思呢?请看下图:


6fdfab89c9cb4a098b80e8413e97e1a7.png


二、自定义打印日志



我们创建一个 Spring Boot 项目后,再创建一个 " UserController " 类,我们预期不给前端返回数据,只是最终能够在 IDEA 控制台显示日志。


@Controller
@ResponseBody
public class UserController {
    // 1. 先得到日志对象
    private final static Logger log =
            LoggerFactory.getLogger(UserController.class);
    @RequestMapping("/hello")
    public void hello() {
        // 2. 使用日志对象提供的打印方法进行日志打印
        log.trace("我是 trace");
        log.debug("我是 debug");
        log.info("我是 info");
        log.warn("我是 warn");
        log.error("我是 error");
    }
}


展示结果:


说明: 刚开始运行时,我们是看不到红色框框中的内容的,我们需要在前端输入 " hello " 这个 URL 后,才能看到下面的日志。这很好理解,因为日志打印的代码是我们自定义生成的,而且写在了 hello 方法内。 如下图所示:


22f6cbac7e5f488b958bf263b0d43409.png


然而,就算我们输入了 " URL ",我们最终发现只打印了三个自定义信息,但是,我们一开始在 hello 方法中,自定义的是五个日志信息,结果却少了两个信息。这就涉及到了【日志级别】的问题了,Spring Boot 框架默认的日志级别是 info,所以,只显示了 info、warn、error.这里不用担心,本篇博客后面会介绍到原因,请继续往下看。


解析代码


1. 先得到日志对象


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


对于上面这段代码,它是固定写法,但我们必须要知道,Logger 类、LoggerFactory 类,它们两是 Spring Boot 框架中 " slf4j " 这个包提供的。

关于 " slf4j ",我们在本篇博客的后面也会介绍到。


5932fadbb6f544daa3ece8168d4283fa.png


此外,使用 " getLogger " 这个方法的时候,我们要指定一个类对象,因为正是这个类对象告诉了 Spring Boot,之后的日志打印要精确到哪个类。


2. 使用日志对象提供的打印方法进行日志打印


下面的五个方法,也是 " slf4j " 这个包所提供的,五个方法实际上对应了五个日志级别,方法传入的参数,就是我们自定义的日志打印。这里需要明确,输出的日志和我们平时使用的 【 System.out.println(); 】不同,这里输出的日志包含在 Spring Boot 内置的框架中,也就是说,它是框架提供的功能。


log.trace("我是 trace");
log.debug("我是 debug");
log.info("我是 info");
log.warn("我是 warn");
log.error("我是 error");


三、日志级别



  1. trace:少许的日志 ( 级别最低 )
  2. debug:调试日志 ( 针对于开发人员调试的场景 )
  3. info:普通信息日志 ( Spring Boot 框架默认的级别 )
  4. warn:警告日志 ( 不影响使用,但仍需要注意问题 )
  5. error:错误日志 ( 级别较高 )
  6. fatal:致命 / 异常日志 ( 系统输出的日志,不能自定义打印 )


六种日志级别,由低到高,越往级别高的日志,接收到的信息越少。


比方说:

当你的日志级别设置为 info 的时候,你只能看到 info、warn、error、fatal.

当你的日志级别设置为 error 的时候,你只能看到 error、fatal.


这很好理解,假设你的项目出现了异常,那么它优先显示错误的日志,因为正常的数据信息与你无关,你也不会对正常的代码进行排查。


3f59fb7247bd46deb08f72c4a50ccb44.png


1. 通过配置文件设置日志级别


为 Spring Boot 项目设置日志级别,我们一般是将配置项放在配置文件中,下面是两种配置文件的配置格式。


983d0df1740a44ec9538b0c7a47a9d0f.png


2. 注意事项


(1) 我们既可以设置整个项目的日志级别 ( 全局配置 );也可以设置局部目录的日志级别。进行局部设置时,精确到某个类对应的目录即可,不需要精确到某个类。


(2) 刚刚上面所说的六种日志级别,都可以通过上图的格式进行配置。

(3) 假设我们配置如下代码:


# 全局配置日志
logging.level.root=warn


我们就可以看到输出日志,只有 warn 和 error,也就是我上面提到的,日志级别越高,接收到的信息就越少。


8f4ca5798013485895ceecd926560eb6.png


(4) 假设我们设置如下代码:


# 设置全局的日志级别
logging.level.root=info
# 设置局部目录的日志级别
logging.level.com.example.demo=warn


当我们同时设置了全局日志和局部日志,那么,指定的局部目录的优先级就会大于全局日志的优先级。


1f944ef605974ef496a1e8b3a3a5cb1b.png


四、日志持久化



日志持久化的意思就是将日志永久地保存到磁盘中。


为什么需要日志持久化呢?


答:我们平时利用 IDEA 随手写一个代码,再进行测试,是感知不到问题的,因为我们都是哪里出错了,再通过即时的日志信息来解决问题就可以了。所以说,IDEA 上的控制台程序只是临时的一份,一般来说,我们运行一次,就会出现一个新的日志信息。然而,在有些场景下,一个项目就需要将日志信息保存下来,以便于出现了问题,进行追溯。由于 Spring Boot 也是为我们后续的 Web 开发服务的,所以框架也实现了一个持久化存储的功能,它依然需要在配置文件中实现。


1. 日志持久化的两种方式


(1) 指定磁盘目录后,由框架自动生成一个文件,并把日志信息放入到此文件中。


logging.file.path=D:/Data


(2) 指定目录 + 文件名,框架会将日志信息放入自定义的文件中


logging.file.name=D:/Data/spring-boot.log


我们以第一种指定目录的方式为例,演示 " UserController " 类,最终发现,框架为我们生成了一个 " spring.log " 这样的文件,我们可以利用记事本的形式打开验证。


cbdb03e9d7b2474f846a57fc4b113adf.png


2. 注意事项


(1) 上面只演示了 properties 配置文件,实际上 yml 配置文件的思想是一样的,只是格式不同罢了。


但是经过我的测试发现,properties 配置文件的目录不能写成中文,否则日志文件就不会自动生成,但 yml 配置文件却可以配置成中文的。这可能是编码问题,也可能是 IDEA 版本问题。但是我认为,如果想避免此问题,还是将目录写成英文的好。实际上,很多场景下,目录和文件确实不宜写成中文。


(2) 框架为我们提供的日志持久化非常的人性化,我们不用担心,在日志文件中,后续的日志信息会将前面的日志信息覆盖。我们可以多运行几次启动类,结果都会发现,文件中的数据是以时间顺序保存着的,然而,文件始终就只有一份。


这让我想起了 Java 中的流对象的,它就可以实现将文本数据按照拼接字符串的方式,每一次生成的数据,就可以放在原先文件的最后方。而在这里,思想是一样的。


如下图所示:


ee09788ac739425ab8971739ea404bb8.png

(3) 也许你会担心如果一个大型项目的日志信息,多的有几个 G 怎么办?那个时候,光是找某个类的日志都会费好大的劲怎么办?


其实,这也不用担心。实际上,框架的底层为我们设计好了一个生成文件的最大内存不超过 10M. 万一超过 10M,就会以编号的方式,重新生成文件,放在同一个目录下。


以后在公司,公司或许有另类的规定,但在日常的学习中,自己做一个项目的话,即使你用到了日志持久化,一般情况下,10M 肯定也到不了。


b45c9440f7f647d7a90d5060eddd765e.png


五、利用 lombok 来做到更简单的日志输出



使用 lombok 这个依赖,添加 " @Slf4j " 注解,它可以替代我们之前的操作。


@Controller
@ResponseBody
@Slf4j // 替代了之前需要通过 LoggerFactory.getLogger 的操作
public class UserController2 {
    @RequestMapping("/hello2")
    public void hello2() {
        log.trace("我是 trace2");
        log.debug("我是 debug2");
        log.info("我是 info2");
        log.warn("我是 warn2");
        log.error("我是 error2");
    }
}


设置局部目录的日志级别为 " trace ",并访问 " hello2 " 这个 URL,查看输出结果:


d27cc106cd7a4c2595eda6e83458f862.png


1. lombok 的使用原理


请看下面的这幅图,它完美诠释了 lombok 的原理,左边是我们加上 " @Slf4j " 注解的代码,它是一个 " .java " 文件,右边代码就是左边 " .java " 文件经编译后,生成的一个 " .class " 文件。在 " .class " 文件中,我们可以清晰地看到,左边的注解已经被转换成了一个 " Logger " 对象了,这也是博客开篇,我们写的第一步。


d8ab8523e4cc4577b755fdb4c3e92cac.png


这样一来我们就明白了,lombok 其实是在 " .java " 文件进行编译的时候,在底层做了一些事情,所以,这就是我们写注解方便的原因。


948a8e337ddf450e849722b25616a885.png


2. 注意事项


上面的 " .class " 文件来源于 【 target 】目录下,当我们创建好一个项目时,它并不是自动生成的,而是当我们点击 main 方法运行时,IDEA 自动帮我们生成的。IDEA 其实就是照着我们平时写的 " .java " 文件,又生成了一个同名的 " .class " 文件,只是我们感知不到而已。


cde1cd52ff9b4406b070094d2ceaedbd.png


我们知道,一个 Java 程序,最终是在 JVM 运行的,但 JVM 实际上只认识 " .class " 文件。所以,如果我们拆解来看,我们平时写的代码,就是放在 " .java " 文件中的,然后再通过编译,变成了 " .class " 文件,最终才给 JVM 运行。


然而,IDEA 帮我们省去了编译的过程,或者说,我们平时根本感受不到编译,只顾着写代码了,但确实,IDEA 帮我们实现了 " 编译 + 运行 " 的整个过程。不过 IDEA 有一点好处,先抛开结果是否符合预期不谈,IDEA 可以在我们写代码的时候,就能够判定是否能正常编译,这是一个非常强大的功能。


此外," .class " 文件,实际上是一个字节码文件,也就是说,它的内容实际上就是以二进制的形式呈现的,只不过,IDEA 帮我做了一些处理,让程序员能够看懂代码。如果我们利用记事本打开 " .class " 文件,就会发现里面的内容是乱码。


3. lombok 提供的更多注解


① 基本注解:


注解 作用
@Getter 自动添加 getter 法
Setter 自动添加 setter 法
@ToString 自动添加 toString 法
@EqualsAndHashCode 自动添加 equals 和 hashCode 法
@NoArgsConstructor 自动添加无参的构造方法
@AllArgsConstructor 自动添加全属性构造方法,顺序按照属性的定义顺序
@NonNull 属性不能为 null
@RequiredArgsConstructor 添加必需属性的构造方法,final + @NonNull 的属性为必需


② 组合注解:


注解 作用
@Data @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor + @NoArgsConstructor


③ 日志注解:


注解 作用
@Slf4j 自动添加一个名为 log 的日志



4. 在 Spring Boot 项目中临时添加 lombok


如果我们的 Spring Boot 项目,在刚开始创建的时候,我们选中我们想要的依赖,那么,我们不用重新创建一个项目,只需要临时添加依赖即可。


第一步,搜索插件。


29469364ff9248e2b932081da7b1c72a.png


第二步,在 pom.xml 文件中,点击 Generate 生成。


337b217ed555470b87554f4a46515d79.png


第三步,选择我们需要添加的依赖。选好后,依赖就会从 maven 仓库引入。


3a3c450175b7420db0107dee5e113977.png


六、关于 Slf4j



" Slf4j " 是 lombok 这个依赖提供的包,不管是我们自己手动引入对象,还是通过注解的方式添加日志," Slf4j " 的核心就是下面这段代码。


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

所以,我们也可以说是 Spring Boot 内置了日志框架 " Slf4j " . 而 " Slf4j " 其实是遵循了门面模式,不管底层的实现代码怎么变," Slf4j " 提供的代码都是固定写法。


所以有时候,我们只需要会用上层的固定写法即可,底层实现的思想就算不理解,也能够将一个项目做的很好。 比方说:当前我们使用的就是 " Slf4j " 提供的一些方法,然而,它的日志实现是基于 " logback " 的。


这就好像," Slf4j " 是直播带货的," logback " 才是真正的生产厂家。


b0d6d8e8296f4cdbac3651c43ab9ad2b.png


这里的门面模式,它和我们正儿八经写的 JDBC 代码差不多,不管我们连接的是 MySQL 数据库,还是 Oracle 数据库,还是其他的数据库…我们开发人员在用的时候,只关注 JDBC 是怎么用的,至于其他的,底层已经为我们封装好了。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
15天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
45 2
|
21天前
|
Java 中间件
SpringBoot入门(6)- 添加Logback日志
SpringBoot入门(6)- 添加Logback日志
64 5
|
19天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
129 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
19天前
|
SQL Oracle 关系型数据库
【赵渝强老师】Oracle的控制文件与归档日志文件
本文介绍了Oracle数据库中的控制文件和归档日志文件。控制文件记录了数据库的物理结构信息,如数据库名、数据文件和联机日志文件的位置等。为了保护数据库,通常会进行控制文件的多路复用。归档日志文件是联机重做日志文件的副本,用于记录数据库的变更历史。文章还提供了相关SQL语句,帮助查看和设置数据库的日志模式。
【赵渝强老师】Oracle的控制文件与归档日志文件
|
26天前
|
Java 应用服务中间件
SpringBoot获取项目文件的绝对路径和相对路径
SpringBoot获取项目文件的绝对路径和相对路径
63 1
SpringBoot获取项目文件的绝对路径和相对路径
|
20天前
|
网络协议 Java
springboot配置hosts文件
springboot配置hosts文件
44 11
|
12天前
|
Java 中间件
SpringBoot入门(6)- 添加Logback日志
SpringBoot入门(6)- 添加Logback日志
26 1
|
17天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
30 2
|
19天前
|
Oracle 关系型数据库 数据库
【赵渝强老师】Oracle的参数文件与告警日志文件
本文介绍了Oracle数据库的参数文件和告警日志文件。参数文件分为初始化参数文件(PFile)和服务器端参数文件(SPFile),在数据库启动时读取并分配资源。告警日志文件记录了数据库的重要活动、错误和警告信息,帮助诊断问题。文中还提供了相关视频讲解和示例代码。
|
26天前
|
存储 前端开发 JavaScript