赞
踩
本篇文章源码位置延续上个章节:SpringBoot_demo
本篇文章内容源码位于上述地址的
com/chenshu/springboot_demo/logging
包下
发现和定位问题: 日志是程序的重要组成部分,它在系统、程序出现错误或异常时提供诊断和解决问题的线索,从而定位问题;只有定位到了问题的位置,程序员才可以对症下药,从而解决问题。
除了发现和定位问题,我们还可以通过日志实现其他功能,比如:
其实所谓日志我们也不是第一次接触了,在Spring Boot这个框架中集成了日志框架,我们在启动项目时在console中所打印的信息其实就是日志。
并且每一条日志记录都默认包含了这些信息:日志打印时间、日志打印级别、线程ID、线程名称、打印日志的类名、日志信息
以上内容就是Spring Boot 输出的控制台日志信息。
通过上述日志信息我们能引出下面几个问题:
我们接下来要讲的内容就是针对上述问题。
Spring Boot中内置的日志门面是SLF4J
,而具体的日志实现是logback
,日志门面是什么?日志实现又是什么?下面给大家简单说说。
门面模式的核心为: 外部与一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用。
解释: 其实门面模式就相当于给各式各样的实现封装了一层统一的外观,对于用户来说不用关心市面上提供的各种各样的具体实现的api是什么,只需要通过门面所提供的统一的api来使用。
市面上有许多日志实现,如:
不同的日志实现,它们的api写法都有所不同,但凡你想去更改一种日志实现,都需要去更改每一处日志代码。
为了解决上述问题,引入了日志门面,而SLF4j就是一种日志门面,通过SLF4J,我们可以随意换另外一个日志框架,应用程序不需要修改任意一行代码,就可以直接上线。
门面模式下的用户视角图示:
自定义打印日志的步骤大概分为下面两步:
由于Spring Boot中内置的是slf4j
的框架,这里我们要选择用org.slf4j
包下的Logger接口:
使用LoggerFactory
中的getLogger()
方法,需要传一个参数来指定打印日志的类:
private static Logger log = LoggerFactory.getLogger(TestController.class);
在LoggingController
里创建一个日志的测试方法,通过日志对象来调用方法,方法名称代表了日志级别,日志级别及使用会在后面说到。
这里我们使用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.
a) 通过日志的保存名称持久化
在application.yml中通过配置日志的名称完成持久化:
# 日志的保存名称
logging:
file:
name: logging_demo.log
只设置名称会将日志默认保存在工作目录下:
点开查看一下:
还可以设置在指定路径下:
logging:
file:
name: /Users/chenshu/Documents/logging/logging_demo.log
b) 通过日志的保存目录持久化
在application.yml中通过配置日志的名称完成持久化:
# 日志的保存路径
logging:
file:
path: /Users/chenshu/Documents/logging
这样的设置会将日志保存在指定的路径下:
特性:
原文件名+日期+.gz
不同的开发环境需要不同的日志级别
日志级别从低到高分别为: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及以上的信息,接下来我来演示一下如何在不同环境的配置文件中设置不同的日志默认级别。
日志级别的配置只需要在配置文件中设置"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
及以上级别的日志信息,看起来非常眼花缭乱:
更精细化的日志级别设置
除了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
对多环境配置文件设置不熟悉的小伙伴可以点击这里:多环境的配置文件设置
需求:将测试环境、开发环境、生产环境的日志分别存储在同一个目录下但命名不同的三个文件中,并且设置测试环境中的日志级别为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.active
为test、dev、prod
,并启动项目。
application.yml:
# 运行环境设置
spring:
profiles:
active: test
分别运行后发现,指定路径确实出现了三个日志文件,并且由于test环境中的日志级别最低,因此文件最大;其次是dev环境;由于没有打印warn级别以上的日志信息,因此prod环境的日志为0bytes
上一篇文章提到过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"); } }
项目的target目录下的classes文件夹中存放了类编译后的字节码文件,找到相应目录下的字节码文件:SpringBoot_demo/target/classes/com/chenshu/springboot_demo/logging/LoggingController.class
把它拉到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字节码文件:
注解 | 作用 |
---|---|
@Getter | 修饰类,自动添加 getter 方法 |
@Setter | 修饰类,自动添加 setter 方法 |
@ToString | 修饰类,自动添加 toString 方法 |
@EqualAndHashCode | 修饰类,自动添加 equals 和 hashcode 方法 |
@NoArgsConstructor | 修饰类,自动添加无参构造方法 |
@AllArgsConstructor | 修饰类,自动添加全属性构造方法,顺序按照属性定义的顺序 |
@NonNull | 修饰属性,属性不能为NULL |
@RequiredArgsConstructor | 修饰类,自动添加所有final或@NonNull修饰过的属性作为参数的构造方法 |
@Data | @Getter、@Setter、@ToString、@EqualsAndHashCode 和 @RequiredArgsConstructor 注解的组合 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。