Spring Boot 日志文件

引言

关于日志

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

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

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

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

一、Spring Boot 日志的格式说明

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

1-4

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

1-5

二、自定义打印日志

我们创建一个 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 方法内。 如下图所示:

1-1

然而,就算我们输入了 " URL ",我们最终发现只打印了三个自定义信息,但是,我们一开始在 hello 方法中,自定义的是五个日志信息,结果却少了两个信息。这就涉及到了【日志级别】的问题了,Spring Boot 框架默认的日志级别是 info,所以,只显示了 info、warn、error.

这里不用担心,本篇博客后面会介绍到原因,请继续往下看。

解析代码

1. 先得到日志对象

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

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

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

1-2

此外,使用 " 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.

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

1-3

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

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

1-4

2. 注意事项

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

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

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

# 全局配置日志

logging.level.root=warn

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

1-5

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

# 设置全局的日志级别
logging.level.root=info

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

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

1-6

四、日志持久化

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

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

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

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

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

logging.file.path=D:/Data

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

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

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

1-7

2. 注意事项

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

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

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

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

如下图所示:

1-8

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

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

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

1-9

五、利用 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,查看输出结果:

2-1

1. lombok 的使用原理

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

2-2

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

2-3

2. 注意事项

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

2-4

我们知道,一个 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 项目,在刚开始创建的时候,我们选中我们想要的依赖,那么,我们不用重新创建一个项目,只需要临时添加依赖即可。

第一步,搜索插件。

4-1

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

4-2

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

4-3

六、关于 Slf4j

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

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

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

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

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

3-1

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十七ing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值