Spring Boot日志

目录

[1 日志概述](#1 日志概述)

[2 日志使用](#2 日志使用)

[3 打印日志](#3 打印日志)

[3.1 在程序中得到日志对象](#3.1 在程序中得到日志对象)

[3.2 日志框架](#3.2 日志框架)

[4 门面模式(外观模式)](#4 门面模式(外观模式))

[4.1 门面模式的定义](#4.1 门面模式的定义)

[4.2 门面模式的实现](#4.2 门面模式的实现)

[5 SLF4J框架](#5 SLF4J框架)

[5.1 不引入日志门面](#5.1 不引入日志门面)

[5.2 引入日志门面](#5.2 引入日志门面)

[6 日志介绍](#6 日志介绍)

[6.1 日志格式](#6.1 日志格式)

[6.2 日志级别](#6.2 日志级别)

[6.2.1 日志级别的分类](#6.2.1 日志级别的分类)

[6.2.2 日志级别的使用](#6.2.2 日志级别的使用)

[7 日志配置](#7 日志配置)

[7.1 日志级别的配置](#7.1 日志级别的配置)

[7.2 日志持久化](#7.2 日志持久化)

[7.3 配置日志文件分割](#7.3 配置日志文件分割)

[7.4 设置日志颜色](#7.4 设置日志颜色)

[7.4.1 启动类设置](#7.4.1 启动类设置)

[7.4.2 添加VM option](#7.4.2 添加VM option)

[8 更简单的日志输出](#8 更简单的日志输出)

[8.1 添加lombok依赖](#8.1 添加lombok依赖)

[8.2 输出日志](#8.2 输出日志)

总结

1 日志概述

从JavaSE部分到现在少不了日志,最初使用System.out.print来打印日志,通过打印日志来发现和定位问题,或者根据日志来分析程序的运行过程,在Spring的学习中,也经常根据控制台的日志来分析和定位问题,除此之外,日志还有更多的用途,比如系统监控和数据采集

2 日志使用

在SpringBoot项目启动的时候默认就有日志输出

我们通过System.out.print来打印日志

java 复制代码
@RestController
public class LoggerController {
    @PostConstruct
    public void logger() {
        System.out.println("打印日志");
    }
}

可以看到,通过System.out.print打印的日志,比SpringBoot打印的日志缺少很多信息

在SpringBoot中内置了日志框架Slf4j,可以直接在程序中调用Slf4j来输出日志

3 打印日志

打印日志的步骤:

1)在程序中得到日志对象

2)使用日志对象输出要打印的内容

3.1 在程序中得到日志对象

在程序中获取日志对象需要使用日志工厂LoggerFactory,这里需要选择slf4j这个接口

java 复制代码
@RestController
public class LoggerController {
    private static Logger logger = LoggerFactory.getLogger(LoggerController.class);
    @PostConstruct
    public void logger() {
        logger.info("需要打印的日志");
    }
}

3.2 日志框架

SLF4J不同其他日志框架,它不是一个真正的日志框架实现,而是一个抽象层,对日志框架制定的一种规范,标准,接口,因此所有的SLF4J不能独立使用,需要和具体的日志框架配合使用

4 门面模式(外观模式)

SLF4J是门面模式的典型应用,但不仅仅使用了门面模式

4.1 门面模式的定义

门面模式 (Facade Pattern)又称为外观模式,提供了一个统一的接口,用来访问子系统中的一群接口,其主要特征是定义了一个高层接口,让子系统更容易使用

门面模式主要包含2中角色:

1)外观角色(Facade):也称门面角色,系统对外的统一接口

2)子系统角色(SubSystem):可以同时有一个或者多个 SubSystem,每个SubSystem都不是一个单独的类,而是一个类的集合,SubSystem并不知道Facade的存在,对于SubSystem来说,Facade只是另一个客户端

例如:去医院看病,需要挂号、门诊、化验、取药,如果病人自己去办会很麻烦,但是如果由接待人员,让接待人员来处理,就会很方便

4.2 门面模式的实现

**场景:**回到家我们会开每个房间的灯,离开家,会关闭房间的灯,如果在家里设置一个总开关,来控制整个家的灯会很方便,此时可以直接使用门面模式来实现

普通模式:

java 复制代码
public class Main {
    public static void main(String[] args) {
        LivingRoomLight livingRoomLight = new LivingRoomLight();
        livingRoomLight.on();
        HallLight hallLight = new HallLight();
        hallLight.on();
        DiningLight diningLight = new DiningLight();
        diningLight.on();
    }
}
interface Light {
    void on();
    void off();
}
/**
 * 客厅灯
 */
class LivingRoomLight implements Light{
    @Override
    public void on() {
        System.out.println("打开客厅灯");
    }

    @Override
    public void off() {
        System.out.println("关闭客厅灯");
    }
}
/**
 * 走廊灯
 */
class HallLight implements Light{
    @Override
    public void on() {
        System.out.println("打开走廊灯");
    }

    @Override
    public void off() {
        System.out.println("关闭走廊灯");
    }
}
/**
 * 餐厅灯
 */
class DiningLight implements Light{
    @Override
    public void on() {
        System.out.println("打开餐厅灯");
    }

    @Override
    public void off() {
        System.out.println("关闭餐厅灯");
    }
}

可以看出在普通模式中,我们需要一步一步的打开灯,这样就会有点麻烦,门面模式就可以帮我们解决这个问题

门面模式(外观模式)

java 复制代码
public class Main {
    public static void main(String[] args) {
        LightFacade lightFacade = new LightFacade();
        lightFacade.lightOn();
    }
}

/**
 * 灯的门面
 */
class LightFacade {
    LivingRoomLight livingRoomLight = new LivingRoomLight();
    HallLight hallLight = new HallLight();
    DiningLight diningLight = new DiningLight();

    public void lightOn() {
        livingRoomLight.on();
        hallLight.on();
        diningLight.on();
    }

    public void lightOff() {
        livingRoomLight.off();
        hallLight.off();
        diningLight.off();
    }
}

interface Light {
    void on();

    void off();
}

/**
 * 客厅灯
 */
class LivingRoomLight implements Light {
    @Override
    public void on() {
        System.out.println("打开客厅灯");
    }

    @Override
    public void off() {
        System.out.println("关闭客厅灯");
    }
}

/**
 * 走廊灯
 */
class HallLight implements Light {
    @Override
    public void on() {
        System.out.println("打开走廊灯");
    }

    @Override
    public void off() {
        System.out.println("关闭走廊灯");
    }
}

/**
 * 餐厅灯
 */
class DiningLight implements Light {
    @Override
    public void on() {
        System.out.println("打开餐厅灯");
    }

    @Override
    public void off() {
        System.out.println("关闭餐厅灯");
    }
}

可以看出使用门面模式可以减少系统之间的相互依赖,使子系统的变化不会影响到调用它的客户端,从而降低了它们之间的耦合

门面模式的优点:

1)减少系统的相互依赖,降低客户端和子系统之间的耦合,使子系统的变化不会影响到调用它的客户端

2)提高灵活性,简化了客户端对子系统的使用难度,客户端无需关心子系统的具体实现,而只需要和门面对象交互即可

3)提高安全性,可以灵活设置访问权限,不在门面对象中开通方法,就无法访问

5 SLF4J框架

SLF4J就是其他日志框架的门面,SLF4J可以理解为是提供日志服务的统一API接口,并不涉及到具体的日志逻辑实现

5.1 不引入日志门面

常见的日志框架由log4j,logback等,如果一个项目已经使用了log4j,而依赖的另一个库假如是Apache Active MQ,它依赖另一个日志框架logback,此时就需要把logback也加载进去

存在问题:

1)不同日志框架的API接口和配置文件不同,如果多个日志框架共存,就必须维护多套配置文件

2)如果要更换日志框架,应用程序将必须修改代码,并且修改过程中可能会存在一些冲突

3)如果引入第三方框架,使用了多套,就需要维护多套配置

5.2 引入日志门面

引入门面日志框架之后,应用程序和日志框架之间就有了统一的API接口,此时应用程序只需要维护一套日志文件配置,当底层实现框架改变时,不需要更改应用程序代码

SLF4J就是这个日志门面,SLF4J可以使代码独立于任意一个特定的日志API

6 日志介绍

6.1 日志格式

6.2 日志级别

日志级别代表日志信息对应问题的严重性,为了更快的筛选符合目标的日志信息

6.2.1 日志级别的分类

之日级别从高到低依次为:FATAL、ERROR、WARN、INFO、DEBUG、TRACE

FATAL:致命信息,表示需要立即被处理的系统级错误

ERROR:错误信息,级别较高的错误日志信息,但不影响系统的继续运行

WARN:警告信息,不影响使用,但需要注意的问题

INFO:普通信息,用于记录应用程序正常运行时的一些信息

DEBUG:调试信息

TRACE:追踪信息

级别越高,收到的信息越少

6.2.2 日志级别的使用

日志级别是开发人员自己设置的,开发人员根据自己的理解来判断该信息的重要程度,针对这些级别,Logger对象分别提供了对应的方法,来输出日志

java 复制代码
@RestController
public class LoggerController {
    private static Logger logger = LoggerFactory.getLogger(LoggerController.class);
    @PostConstruct
    public void logger() {
        logger.error("error日志");
        logger.warn("warn日志");
        logger.info("info日志");
        logger.debug("debug日志");
        logger.trace("trace日志");
    }
}

可以看出只打印了erroe、warn、info级别的日志,这是因为日志的默认级别是info,所以只会打印大于等于此级别的日志

7 日志配置

上述日志的使用,日志框架支持我们更灵活的输出日志,包括内容,格式等

7.1 日志级别的配置

java 复制代码
logging:
  level:
    root: debug

7.2 日志持久化

以上的日志都是输出在控制台上的,在线上环境中,需要把日志保存下来,一遍出现问题之后追溯问题,把日志保存下来就叫持久化

日志持久化有两中方式

1)配置日志文件名

logging.file.name

2)配置日志的存储目录

logging.file.path

配置日志文件的路径和文件名

java 复制代码
logging:
  file:
    name: logger/springboot.log

后面可以跟绝对路径或者相对路径

此时日志内容就保存在对应的目录下

配置日志文件的保存路径

java 复制代码
logging:
  file:
    path: E:/logger

这种方式只能设置日志的路径,文件名为固定的spring.log

注意:

logging.file.namelogging.file.path两个都配置的情况下只能生效一个,以logging.file.name为准

7.3 配置日志文件分割

如果日志都放在一个文件中,随着项目的运行,日志文件会越来越大,因此需要对日志文件进行分割,如果不进行配置的话,就会自动配置,默认日志文件超过10MB就进行分割

|--------------------------------------------------|------------------|----------------------------------|
| 配置项 | 说明 | 默认值 |
| logging.logback.rollingpolicy.fil e-name-pattern | ⽇志分割后的⽂件名 格式 | ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz |
| logging.logback.rollingpolicy.m ax-file-size | ⽇志⽂件超过这个⼤ ⼩就⾃动分割 | 10MB |

配置文件分割:

java 复制代码
logging:
  file:
    path: E:/logger
  logback:
    rollingpolicy:
      max-file-size: 2KB
      file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i

7.4 设置日志颜色

7.4.1 启动类设置

7.4.2 添加VM option

启动控制台,观察颜色

8 更简单的日志输出

每次使用LoggerFactory.getLogger(xxx.class)输出日志非常繁琐,并且每个类都要添加一遍,lombok给我们提供了一种更简单的方式

1)添加lombok框架支持

2)使用@slf4j注解输出日志

8.1 添加lombok依赖

java 复制代码
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

8.2 输出日志

java 复制代码
@Slf4j
@RestController
public class LoggerController {
    @PostConstruct
    public void logger() {
        log.error("error日志");
        log.warn("warn日志");
        log.info("info日志");
        log.debug("debug日志");
        log.trace("trace日志");
    }
}

lombok提供的@Slf4j会帮我们提供一个日志对象log,直接使用即可

总结

1)日志是程序中的重要组成部分,使⽤日志可以快速的发现和定位问题,Spring Boot 提供了日志框架,默认情况下使用的是 info 日志级别将日志输出到控制台的,我们可以通过 lombok 提供的 @Slf4j 注解和 log 对象快速的打印自定义日志

2)日志包含6个级别,日志级别越高,收到的信息越少,可以通过配置日志的保存名称或者日志目录来将日志持久化

相关推荐
老猿讲编程7 分钟前
一个例子来说明Ada语言的实时性支持
开发语言·ada
Chrikk1 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*1 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue1 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man1 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
测开小菜鸟1 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity2 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天2 小时前
java的threadlocal为何内存泄漏
java
caridle2 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
萧鼎2 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步