Spring Boot 日志

目录

一、为什么要学习日志

二、认识日志格式

三、日志使用

打印日志

步骤

日志框架介绍

门面模式(外观模式)

门面模式的实现

门面模式的优点

四、日志级别

日志级别分类

日志级别的使用

日志配置

配置日志级别

日志持久化

配置日志文件分割

五、更简单的日志输出


一、为什么要学习日志

日志对我们来说并不陌生,从JavaSE部分,我们就在使用 System.out.print 来打印日志了.通过打

印日志来发现和定位问题,或者根据日志来分析程序的运行过程.在 Spring 的学习中,也经常根据控制台的日志来分析和定位问题.

随着项目的复杂度提升,我们对日志的打印也有了更高的需求,而不仅仅是定位排查问题.

比如需要记录一些用户的操作记录(一些审计公司会要求),也可能需要使用日志来记录用户的一些喜好,把日志持久化,后续进行数据分析等.但是 System.out.print 不能很好的满足我们的需求,我们就需要使用一些专门日志框架(专业的事情交给专业的人去做).

二、认识日志格式

1️⃣时间日期:精确到毫秒

2️⃣日志级别:ERROR,WARN,INFO,DEBUG或TRACE

3️⃣进程 ID

4️⃣线程名

5️⃣Logger 名(通常使用源代码的类名)

6️⃣日志内容

三、日志使用

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

打印日志

步骤

• 在程序中得到日志对象.

需要使用志工厂 LoggerFactory

java 复制代码
private static Logger logger = LoggerFactory.getLogger(CaptchaController.class);

LoggerFactory.getLogger 需要传递⼀个参数, 标识这个日志的名称. 这样可以更清晰的知道是哪个类输出的日志. 当有问题时, 可以更方便直观的定位到问题类

• 使用日志对象输出要打印的内容.

日志对象的打印方法有很多种,我们可以先使用 info() 方法来输出日志

java 复制代码
logger.info("Logger生成验证码: " + code);

日志框架介绍

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

门面模式(外观模式)

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

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

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

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

子系统角色(SubSystem):可以同时有一个或多个SubSystem.每个SubSytem都不是一个单独的类,

而是一个类的集合.SubSystem并不知道Facade的存在,对于SubSystem而言,Facade只是另一个客户端而已(即Facade对SubSystem透明)

门面模式的实现

场景: 回家, 我们会开各个屋的灯. 离开家时, 会关闭各个屋的灯. 如果家里设置⼀个总开关, 来控制整个屋的灯就会很方便.

没建门面前

java 复制代码
package com.example.demo.facade;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public interface Light {
    void on();
    void off();
}

public HallLight implements Light {
    private static Logger logger = LoggerFactory.getLogger(HallLight.class);

    @Override
    public void on() {
        logger.info("打开走廊灯");
    }

    @Override
    public void off() {
        logger.info("关闭走廊灯");
    }
}

public LivingRoomLight implements Light {
    private static Logger logger = LoggerFactory.getLogger(LivingRoomLight.class);

    @Override
    public void on() {
        logger.info("打开客厅灯");
    }

    @Override
    public void off() {
        logger.info("关闭客厅灯");
    }
}

public BedRoomLight implements Light {
    private static Logger logger = LoggerFactory.getLogger(BedRoomLight.class);

    @Override
    public void on() {
        logger.info("打开卧室灯");
    }

    @Override
    public void off() {
        logger.info("关闭卧室灯");
    }
}

public class Main {
    public static void main(String[] args) {
        HallLight hallLight = new HallLight();
        LivingRoomLight livingRoomLight = new LivingRoomLight();
        BedRoomLight bedRoomLight = new BedRoomLight();
        hallLight.on();
        livingRoomLight.on();
        bedRoomLight.on();
    }
}

我们使用门面模式的实现

java 复制代码
package com.example.demo.facade;

public class LightFacade {
    void lightOn() {
        HallLight hallLight = new HallLight();
        LivingRoomLight livingRoomLight = new LivingRoomLight();
        BedRoomLight bedRoomLight = new BedRoomLight();
        hallLight.on();
        livingRoomLight.on();
        bedRoomLight.on();
    }

    void lightOff() {
        HallLight hallLight = new HallLight();
        LivingRoomLight livingRoomLight = new LivingRoomLight();
        BedRoomLight bedRoomLight = new BedRoomLight();
        hallLight.off();
        livingRoomLight.off();
        bedRoomLight.off();
    }
}
java 复制代码
package com.example.demo.facade;

public class Main {
    public static void main(String[] args) {
        LightFacade lightFacade = new LightFacade();
        lightFacade.lightOn();
        lightFacade.lightOff();
    }
}

门面模式的优点

●减少了系统的相互依赖,实现了客户端与子系统的耦合关系,这使得子系统的变化不会影响到调用它的客户端.

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

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

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

四、日志级别

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

日志级别分类

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

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

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

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

🔺INFO: 普通信息,用于记录应用程序正常运行时的一些信息,例如系统启动完成、请求处理完成等.

🔺DEBUG: 调试信息,需要调试时候的关键信息打印.

🔺TRACE: 追踪信息,比 DEBUG 更细粒度的信息事件(除非有特殊用意,否则请使用 DEBUG级别替代).

日志级别的使用

java 复制代码
package com.example.demo.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/logger")
@RestController
public class LoggerLevelController {
    private static Logger logger = LoggerFactory.getLogger(LoggerLevelController.class);

    @RequestMapping("/print")
    public String print() {
        logger.trace("trace级别日志......");
        logger.debug("debug级别日志......");
        logger.info("info级别日志......");
        logger.warn("warn级别日志......");
        logger.error("error级别日志......");
        return "打印日志";
    }
}

结果发现, 只打印了info, warn和error级别的日志.

这与日志级别的配置有关, 日志的输出级别默认是 info 级别, 所以只会打印大于等于此级别的日志, 也就是 info, warn和error.

日志配置

配置日志级别

logging:
  level:
    root: debug

日志级别也可以分类来设置

logging:
  level:
    root: info
    com:
      example:
        demo:
          controller: trace

日志持久化

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

日志持久化有两种方式

1️⃣配置日志文件名

logging:
  file:
    name: logger/springboot.log

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

2️⃣配置日志的存储目录

logging:
  file:
    path: D:/temp
logging:
  file:
    path: D:/temp/aaa/springboot.log

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

⚠️logging.file.name 和 logging.file.path 两个都配置的情况下, 只生效其一, 以 logging.file.name 为准.

配置日志文件分割

如果我们的日志都放在一个文件中, 随着项目的运行, 日志文件会越来越大, 需要对日志文件进行分割.

java 复制代码
logging:
  file:
    #path: D:/temp/aaa/springboot.log
    name: logger/springboot.log
  logback:
    rollingpolicy:
      max-file-size: 1KB
      file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i

1.日志文件超过 1KB 就分割(设置 1KB 是为了更好展示.企业开发通常设置为200M,500M等,此处没有明确标准)

2.分割后的日志文件名为:日志名.日期.索引

五、更简单的日志输出

每次都使用 LoggerFactory.getLogger(xxx.class) 很繁琐, 且每个类都添加一遍, lombok 给我们提供了⼀种更简单的方式.

1️⃣添加 lombok 框架支持

2️⃣使用 @Slf4j 注解输出日志

lombok 提供的 @Slf4j 会帮我们提供⼀个日志对象 log, 我们直接使用就可以.

java 复制代码
package com.example.demo.controller;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RequestMapping("/logger2")
@RestController
public class LoggerLevelController2 {
    //private static Logger logger = LoggerFactory.getLogger(LoggerLevelController2.class);

    @RequestMapping("/print")
    public String print() {
        log.trace("trace级别日志......");
        log.debug("debug级别日志......");
        log.info("info级别日志......");
        log.warn("warn级别日志......");
        log.error("error级别日志......");
        return "打印日志";
    }
}
相关推荐
算法与编程之美11 分钟前
冒泡排序
java·开发语言·数据结构·算法·排序算法
Aphelios38012 分钟前
Java 学习记录:基础到进阶之路(一)
java·开发语言·学习·idea
程序员麻辣烫21 分钟前
晋升系列4:学习方法
java·数据库·程序人生·学习方法
爱学习的小王!28 分钟前
有关MyBatis的动态SQL
java·笔记·sql·学习·mybatis
斑鸠喳喳30 分钟前
模块系统 JPMS
java·后端
苦逼的老王32 分钟前
java之uniapp实现门店地图
java·开发语言·uni-app
austin流川枫33 分钟前
如何基于缓存设计实现一个商品最近搜索记录功能
java·redis
无际单片机编程1 小时前
单片机OTA升级中Bootloader怎么判断APP有没有问题?
java·stm32·单片机·嵌入式硬件·嵌入式
A boy CDEF girl1 小时前
【JavaEE】多线程进阶(2)
java·java-ee