目录
一. 日志概述
二. 日志的使用
1. 打印日志
(1) 获取日志对象
(2) 输出要打印的内容
2. 日志框架简介
(1) 门面模式简介
(2) SLF4J 框架简介
3. 日志的格式
4. 日志的级别
5. 日志配置
(1) 配置日志级别
(2) 日志持久化存储
① 配置日志文件名
② 配置日志的存储目录
(3) 日志文件分割
(4) 更简单的日志输出
一. 日志概述
日志对我们来说并不陌生, 从JavaSE部分开始, 我们就在使用 System.out.print 来打印日志了. 通过打印日志来发现和定位问题, 或者根据日志来分析程序的运行过程. 在Spring的学习中, 我们也经常根据控制台的日志来分析和定位问题.
随着项目的复杂度提升, 我们对日志的打印也有了更高的需求, 不仅仅是定位排查问题.
比如 记录一些用户的操作记录; 使用日志来记录用户的一些喜好; 把日志持久化, 后续进行数据分析等. 但是 System.out.print 不能很好的满足我们的需求, 此时我们就需要引入一些专门的日志框架来完成这样的任务.
二. 日志的使用
1. 打印日志
打印日志的步骤:
step1: 从程序中获取日志对象.
step2: 使用日志对象输出要打印的内容.
(1) 获取日志对象
在程序中获取日志对象需要使用日志工厂 LoggerFactory, 如下代码所示:
package com.jrj.logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoggerController {
public static Logger logger = LoggerFactory.getLogger(LoggerController.class);
}
[注意]:
① Logger 对象是属于 org.slf4j 包下的, 不要导错包.
② LoggerFactory.getLogger 需要传递一个参数. 参数类型是一个类对象, 传入的是哪个类的类对象, 就表示哪个类在打印日志.
(2) 输出要打印的内容
日志对象的打印方法有很多种, 我们这里先使用 logger.info() 方法打印.
@RestController
public class LoggerController {
public static Logger logger = LoggerFactory.getLogger(LoggerController.class);
@RequestMapping("/printLogger")
public static String printLogger(){
logger.info("打印日志");
return "打印日志";
}
}
打印结果如下:
2. 日志框架简介
SLF4J不同于其他日志框架. 它并不是一个真正的日志实现, 而是一个抽象层, 一种接口. 所有SLF4J并不能独立使用, 需要和具体的更底层的日志框架配合使用.
(1) 门面模式简介
门面模式又称为外观模式. 提供了一个统一的接口, 用来访问子系统中的一群接口. 其主要特征是 定义了一个高层接口, 让子系统更容易使用.
(2) SLF4J 框架简介
SLF4J 就是其他日志框架的门面. SLF4J可以理解为是提供日志服务的统一API接口, 并不涉及到具体的日志逻辑实现.
存在的问题:
- 不同日志框架的API接口和配置文件不同. 如果多个日志框架共存, 那么不得不维护多套配置文件(这个配置文件是指用户自定义的配置文件).
- 如果要更换日志框架, 应用程序将不得不修改代码, 并且修改过程中可能会存在⼀些代码冲突.
- 如果引入的第三方框架, 使用了多套, 那就不得不维护多套配置.
3. 日志的格式
通过打印出的日志我们可以看到, 日志内容从左到右依次为:
① 日期, 时间 (精确到毫秒)
② 日志级别
③ 进程ID
④ 打印日志的项目名
⑤ 线程名
⑥ Logger 名
⑦ 日志内容
4. 日志的级别
日志级别代表着日志信息对应问题的严重性, 方便更快地筛选符合目标的日志信息.
日志的级别从高到低依次为: FATAL, ERROR, WARN, INFO, DEBUG, TRACE
- FATAL: 致命信息, 表示需要立即被处理的系统级错误.
- ERROR: 错误信息, 级别较高的错误日志信息,但仍然不影响系统的继续运行.
- WARN: 警告信息, 不影响使用,但需要注意的问题
- INFO: 普通信息, 用于记录应用程序正常运行时的⼀些信息,例如系统启动完成、请求处理完成等.
- DEBUG: 调试信息, 需要调试时候的关键信息打印.
- TRACE: 追踪信息, 比DEBUG更细粒度的信息事件 (除非有特殊用意,否则一般使用DEBUG级别替代)
[注]: 一般情况下, 日志级别越高, 收到的消息越少.
例如: 出现fatal级别的日志, 表示服务器出现了某种程度上的不可用, 需要程序员紧急介入处理, 一般在一个程序的生命周期中fatal级别的日志只会出现一次.
我们下来打印一下不同级别的日志观察一下:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/logger")
public class LoggerController {
public static Logger logger = LoggerFactory.getLogger(LoggerController.class);
@RequestMapping("/printLogger")
public static String printLogger(){
logger.info("打印info日志");
logger.error("打印error日志");
logger.warn("打印warn日志");
logger.debug("打印debug日志");
logger.trace("打印trace日志");
return "打印日志";
}
}
从打印结果我们可以看到: 只打印出了 INFO, WARN, ERROR 级别的日志. 却没有打印出 DEBUG 和 TRACE 级别的日志. 这是因为日志的输出默认最低级别是 INFO 级别, 也就是说, 级别低于INFO的都不会打印出来.
5. 日志配置
(1) 配置日志级别
日志的级别配置只需要在配置文件中设置 "logging.level" 配置项即可.
properties:
logging.level.root=debug
yml:
logging:
level:
root: debug
运行后效果:
后续我们在项目中配置日志级别时, properties 和 yml 只需要配置其中的一个即可.
root 表示的是该项目下的所有文件的日志. 我们也可以通过 在level下面加上软件包的树形结构 来限定 只有指定包下文件的日志从指定级别开始打印.
logging.level.org.example.practice.LoggerController=trace
(2) 日志持久化存储
以上的日志都是输出在控制台的 (日志存在内存中), 但是我们有时需要持久存储日志 (将日志存到硬盘中) 以便出现问题之后追溯问题. 那如何持久化存储日志呢? --> 日志的持久化存储有两种方式
① 配置日志文件名
# 设置⽇志⽂件的⽂件名
logging:
file:
name: logger/springboot.log
② 配置日志的存储目录
# 设置⽇志⽂件的⽬录
logging:
file:
path: F:/temp
配置好后, 运行程序, 会发现指定路径下多出一个文件.
- 配置日志文件的存储路径, 可以是相对路径, 可以是绝对路径. 路径中只可以设置路径(不能设置文件名称).
- logging.file.name 和 logging.file.path 两者都配置的情况下, 只生效一个 (以 logging.file.name 为准)
(3) 日志文件分割
如果我们的日志都放在一个文件中, 随着项目的运行, 日志文件就会越来越大. 此时我们就需要对日志文件进行分割.
当然日志框架也考虑到了这一点. 所以我们如果不手动分割的话, 就会自动进行分割 (默认日志文件大小超过10M就进行分割).
logging:
logback:
rollingpolicy:
max-file-size: 2KB
file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i
上述代码中的配置表示: ① 最大日志文件大小为2KB (大小超过2KB就分割) ; ② 分割后的日志文件名为: 日志名. 日期. 索引
将上述代码运行, 并且多打印几次日志, 我们得到:
(4) 更简单的日志输出
每次都使用LoggerFactory很繁琐,每个类都要添加一遍Logger对象,于是lombok就为我们提供了一种特别方便的方式.
- 添加lombok依赖.
- 使用 @Slf4j注解.
@Slf4j 注解产生Logger对象(对象名默认为log). 使用log对象进行日志输出.
@RestController
@Slf4j
public class LoggerController {
public static String printLogger(){
log.info("打印info日志");
log.error("打印error日志");
log.warn("打印warn日志");
log.debug("打印debug日志");
log.trace("打印trace日志");
return "打印日志";
}
}
通过结果我们可以看到, 同样可以正常打印日志.