目录
[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)配置日志文件名
2)配置日志的存储目录
logging.file.path
配置日志文件的路径和文件名
java
logging:
file:
name: logger/springboot.log
后面可以跟绝对路径或者相对路径
此时日志内容就保存在对应的目录下
配置日志文件的保存路径
java
logging:
file:
path: E:/logger
这种方式只能设置日志的路径,文件名为固定的spring.log
注意:
logging.file.name和logging.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个级别,日志级别越高,收到的信息越少,可以通过配置日志的保存名称或者日志目录来将日志持久化