
目录
一、为什么要学习日志
日志对我们来说并不陌生,从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 "打印日志";
}
}