(目录)


1. 日志的作用

日志是程序的重要组成部分,在程序报错的时候,如果我们不看日志,是很难排查出错误的,除非你真的是很有经验.所以日志最主要的作用就是排除和定位问题.

日志提供的功能:

  1. 记录⽤户登录⽇志,⽅便分析⽤户是正常登录还是恶意⽤户。
  2. 记录系统的操作⽇志,⽅便数据恢复和定位操作⼈。
  3. 记录程序的执⾏时间,⽅便为以后优化程序提供数据⽀持

举例:

  1. 记录⽤户登录⽇志,⽅便分析⽤户是正常登录还是恶意⽤户。 假设有一个平台,一天被登录了10万次,登录日志暴增! 正常情况下,可能一天 ,顶多1 万多点。 但是,此时我们发现这一天的登录日志暴增,并且查到有好几个账号,在这一天里登录上万次!这还需要想嘛?肯定有人对着几个账号进行了恶意登录!(盗号) 我们马上就可以对其进行冻结操作,让真正的用户修改密码信息后,才能恢复正常使用。 甚至说:直接拉黑名单。  

  2. 记录系统的操作⽇志,⽅便数据恢复和定位操作⼈。 试想一下:当某个人在某个时间段进行了一次错误操作,而操作日志会把这个操作的具体信息给记录下来了(操作人,操作时间,执行的操作,数据改动的前后状态)。 此时,我们就可以根据这个日志,锁定 执行该操作的人(bb 他一顿),让其 对 操作数据 进行 回滚(还原) 操作【根据日志的记录】。  

  3. 记录程序的执⾏时间,⽅便为以后优化程序提供数据⽀持。 你可以理解为:日志,记录了每一个方法的执行时间(在一个统一的地方记录)。 就是说:记录每一个方法之前,我们先做一个拦截,每一个方法执行之后,再做一个拦截。 这样我们就能记录每一个方法的执行时间了。 那么,记录方法的执行时间有什么作用呢? 可以方便我们以后 对 程序进行针对性的优化。 公司里面的 主管/经理,每周都会做一件事:按照方法执行时间来对日志进行排序。 将执行时间最长的 前十个方法,挑出来进行优化。 要想进行优化,没有日志,你怎么知道哪些方法的运行时间很长。 更别提对这些方法进行优化,提升执行效率。


2. 日志怎么用

在我们启动 SpringBoot 项目的时候就会输出日志:

image-20220813221346552

只不过,上面这些日志,不具有持久化存储的特性【没存储到 硬盘中】

简单来说:

上述的这些日志,就是进行一个简单的打印,不会存储到硬盘。

也就是说 启动下一个项目的时候,上一次启动项目的日志是没有被记录下来的。


通过上述⽇志信息我们能发现以下 3 个问题:

1、Spring Boot 内置了⽇志框架(不然也输出不了⽇志)。   2、默认情况下,输出的⽇志并⾮是开发者定义和打印的,而是 系统输出的日志,那开发者怎么在程序中⾃定义打印⽇志呢?

有的可能会说:使用 sout 输出语句进行打印,不就行了。 答案是不行的,因为 sout 语句 存在 几个问题!

image-20220813224841358

3、⽇志默认是打印在控制台上的,⽽控制台的⽇志是不能被保存的,那么怎么把⽇志永久的保存下来呢


3. 自定义日志打印

主要分两个步骤:

  1. 在一个类中先获得打印日志对象(日志框架提供的日志对象,而日志框架默认已经集成到 SpringBoot 里了)
  2. 使用日志对象提供的方法实现日志的打印

3.1 得到日志对象

得到日志对象 Logger ,它来自于 slf4j,不要导错了包,在程序中获取⽇志对象需要使⽤⽇志⼯⼚ LoggerFactory

image-20220814105426876


3.2 使用日志对象提供的方法打印日志

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@ResponseBody
public class UserController {

//1. 先得到日志对象(来自 slf4j)
    private static final Logger log =
        LoggerFactory.getLogger(UserController.class); //设置当前的类型

    @RequestMapping("/sayhi")
    public void sayHi(){
        //2. 使用日志对象提供的打印方法进行日志打印
        log.trace("我是 trace");
        log.debug("我是 debug");
        log.info("我是 info");
        log.warn("我是 warn");
        log.error("我是 error");

    }
}

img

有些没打印,因为他只会打印跟他同级别的或者比他级别高的日志,他这里默认是 info 级别.


3.3 日志格式说明

日志具体表示什么信息呢?

image-20220814105710841


4. 日志级别

反馈一些需要的日志,并不需要把所有的都打印出来

就像是如果你是一家 2 万人的公司的老板,需要每天看他们的反馈信息,难道每个人都看吗?这显然看不完,你只需要看一些领头的就行…


4.1 日志级别分类

日志级别分为:

  1. trace: 微量,少许的意思(级别最低)
  2. debug: 调试日志
  3. info: 普通信息日志
  4. warn: 警告日志
  5. error: 错误日志
  6. fatal: 致命的日志(系统输出的日志,不能自定义打印)

日志级别的顺序:

image-20220814105924386

越往上接收到的消息就越少。

注意:

fatal 是不支持打印的,因为你程序都崩溃了,你还打印个锤子。。。 而且, 日志对象 也没有提供 关于 fatal 的 方法、

image-20220814110116927


4.2 日志级别的配置

① 全局日志级别设置

⽇志级别配置只需要在配置⽂件中设置“logging.level”配置项即可:

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

# 设置局部文件夹的日志级别
logging.level.com.example.demo.UserController=trace

image-20220814110407270

image-20220814110459428

之前的 info 级别日志就没打印了.


② 局部日志级别设置

方法也很简单!!!

还是通过 logger.lever 来进行设置! 不同的就是:将 root 修改成 你进行局部设置日志级别的对象(文件夹 / 类)。

image-20220814110706589


现在有一个问题: 在全局日志级别 和 局部日志级别,都被设置的情况下,哪一个的优先级最高?

是 全局日志级别设置,直接全部覆盖! 局部日志级别设置,并没有生效! 即: 全局日志级别设置 比 局部日志级别设置 的 优先级要高!   还是 全局日志等级 的 设置,虽然起到了作用。 但是 设置了 局部日志级别 的 对象,遵守的是局部日志级别的设置。 即: 局部日志级别设置,比 全局日志级别设置 的 优先级要高

image-20220814110822985

日常开发中,关于日志级别的设置,不会精确到类的! 最多精确到 文件夹级别。


5. 日志持久化

前面打印的日志,只是一闪而过!【打印完就没了!】

因为,以上的⽇志都是输出在控制台上的,而控制台上的信息是不会被存储到硬盘上的。 项目重启之后,之前的日志信息就没了。

image-20220814110951440

然⽽在⽣产环境上,我们是需要将⽇志保存下来的。 以便出现问题之后追溯问题,把⽇志保存到磁盘的过程就叫做持久化。


日志持久化(将日志永久的保存到磁盘的某个位置)

  1. 在配置文件中设置日志的保存路径,当设置了保存路径之后,那么日志就会自动进行持久化存储。

  2. 在配置文件中设置日志保存的文件名,日志也会自动进行持久化存储。

#设置日志保存的目录 写法一
logging.file.path=D:\\log
# 设置日志保存的目录写法二
logging.file.path=D:/log

image-20220814111339533


这个我就直接演示了。 就是把 path 改成 name 了。

# 设置日志的保存名称
logging.file.name=G:\\log\\spring-boot.log

image-20220814111523618

下面我们来验证一下效果:

image-20220814111545050


但是!还存在一个问题!!!

如果 日志文件 很大(将所有的日志信息,都存储到一个文件夹里). 那我们查看起来,不就很麻烦了!!!   那么,有什么方法是可以限制 日志文件的大小呢? 这个问题,不是我们该操心的!   因为,日志文件的大小,默认是 10MB

image-20220814115008017

日志文件大小超过了 10MB 的时候,会自动创建新的 日志文件

其命名格式,就像我们创建副本一样:

spring-boot(1).log,spring-boot(2).log,spring-boot(3).log…

另外,是可用通过上述的方法进行设置 日志文件的大小的。

image-20220814115050864


6. 更简单的实现自定义日志的打印

每次都使⽤ LoggerFactory.getLogger(xxx.class) 很繁琐,且每个类都添加⼀遍,也很麻烦,这⾥讲⼀ 种更好⽤的⽇志输出⽅式,使⽤ lombok 来更简单的输出。

  1. 添加 lombok 框架⽀持。
  2. 使⽤ @slf4j 注解输出⽇志。

6.1 准备工作,添加 lombok 到项目中

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

6.2 使用 @Slf4j 得到日志对象

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@ResponseBody
@Slf4j //替代了之前需要通过 LoggerFactory.getLogger 操作
public class UserController {

//1. 先得到日志对象(来自 slf4j)
//    private static final Logger log =
//        LoggerFactory.getLogger(UserController.class); //设置当前的类型

    @RequestMapping("/sayhi")
    public void sayHi(){
        //2. 使用日志对象提供的打印方法进行日志打印
        log.trace("我是 trace");
        log.debug("我是 debug");
        log.info("我是 info");
        log.warn("我是 warn");
        log.error("我是 error");

    }
}

注意:使⽤ @Slf4j 注解,在程序中使⽤ log 对象即可输⼊⽇志,并且只能使⽤ log 对象才能输出,这 是 lombok 提供的对象名

image-20220814120046109


6.3 lombok 原理解释

为什么 加上 @Slf4j,就可以省略第一步,直接得到一个 log 对象呢?

.class文件,他是给我们转换了的:

image-20220814120016638

Java 程序的运⾏原理:

image-20220814115922895

Lombok 的作⽤如下图所示:

image-20220814115934347


6.4 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 的⽇志,使⽤ slf4j

总结:

⽇志是程序中的重要组成部分,使⽤⽇志可以快速的发现和定位问题。

Spring Boot 内容了⽇志框架。

默认情况下使⽤的是 info ⽇志级别将⽇志输出到控制台的。

我们可以通过 lombok 提供的 @Slf4j 注解和 log 对象快速的打印⾃定义⽇志。

⽇志包含 6 个级别:

  • trace:微量,少许的意思,级别最低;
  • debug:需要调试时候的关键信息打印;
  • info:普通的打印信息;
  • warn:警告,不影响使⽤,但需要注意的问题;
  • error:错误信息,级别较⾼的错误⽇志信息;
  • fatal:致命的,因为代码异常导致程序退出执⾏的事件。

⽇志级别依次提升,⽽⽇志级别越⾼,收到的⽇志信息也就越少,我们可以通过配置⽇志的保存名称或保存⽬录来将⽇志永久地保存下来。