本系列共涉及4个框架:Sping,SpringBoot,Spring MVC,Mybatis。
博客涉及框架的重要知识点,根据序号学习即可。
1、日志概述
1.1学习日志的必要性
在第一次学习编程语言的时候,我们就在使用printf或者System.out.println等打印语句打印日志了,为什么日志这么重要呢?因为在编程的学习过程中,不可能不出错,所以打印日志是最快来发现和定位问题的,或者说可以根据日志来分析程序的运行过程。
1.2日志的用途
(1)系统监控:在大数据时代,监控几乎是一个成熟系统了,我们可以通过日志记录这个系统的运行状态,响应状态,在关键时刻某规则超过了阈值则立马报警
(2)数据采集:日志可以采集数据为数据统计、推荐排序做出巨大贡献。【数据统计:统计某页面的浏览量(PV),访客量(UV),点击量等来优化公司运营策略】【推荐排序:目前推荐排序应用在各大领域,比如我们熟悉的抖音、拼多多等日流量爆炸的应用,点击推荐。数据采集是推荐排序工作中的非常重要的一步,系统通过日志记录用户的浏览历史,停留时间等,算法人员就会通过这些数据训练模型,给用户做推荐】
(3)日志审计:随着互联网的发展,越来越多的公司关键业务运行在网络在上,网络安全越来越受大家关注。通过日志分析,在公司中可以清楚的知道是谁做了某些违规操作,或者是信息泄露等等。
2、日志使用
2.1打印日志
(1)在SpringBoot项目启动时,就会有默认的日志打印,如下图所示,那么这些日志和System.out.println()打印的有什么区别呢?
可以知道System.out.println()只会打印括号里面的内容,相较于SpringBoot的打印少了很多信息。
然而SpringBoot内置了日志框架Slf4j,我们可以在程序中直接调用Slf4j来输出日志。
(2)打印日志的步骤:
①在程序中获取日志对象
②使用日志对象打印日志
注意:导包的时候别导错了!!!!Logger对象时属于org.slf4j包下的
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LoggerController {
//在程序中获取日志对象需要使用日志工厂LoggerFactory
//LoggerFactory.getLogger需要传递一个参数,标识这个日志的名称,这样可以更清晰的知道是哪个类输出的日志,更好定位
private static Logger logger = LoggerFactory.getLogger(LoggerController.class);
//使用日志对象打印日志,info()只是一种打印日志的方法
@RequestMapping("/logger")
public String logger(){
logger.info("-------------要输出的日志------------");
return "打印日志";
}
}
2.2日志框架
(1)
(2)SLF4J不同于其他日志框架,它不是一个真正的日志实现,而是一个抽象层,对日志框架制定的一种规范,标准,接口。所有SLF4J并不能独立使用,需要和具体的日志框架配合使用。SLF4J就是其他日志框架的门面,可以理解为是提供日志服务事务统一API接口,并不涉及到具体的日志逻辑框架
(3)那么为什么要SLF4J当门面呢?而不直接使用日志框架(即具体的日志逻辑)。当然这肯定是有原因的——假如不引入日志门面,在开发某个项目时,已经使用了log4j,然而在功能的实现时,需要依赖另一个日志框架logback,那么你又要把logback也加载进去,这样导致的就是有两个日志框架共存,不好维护配置文件,更换日志框架时修改代码,修改的代码有冲突怎么办?所以这就体现出引入日志门面的好处了,引入之后,应用程序和日志框架之间有了统一的API接口,此时只需要维护一套日志文件配置,且当底层实现框架改变时,也不需要更改应用程序的代码了
2.3门面模式(外观模式)
(1)门面模式
①SLF4J是门面模式的典型应用(但是不仅仅使用了门面模式)
②定义:门面模式(Facade Pattern)又称为外观模式,提供了一个统一的接口,用来访问子系统中的一群接口。主要特征是定义了一个高层接口,让子系统更容易使用
③门面模式主要包含2种角色:
外观角色(Facade):也称门面角色,系统对外的统一接口
子系统角色(SubSystem):可以同时有一个或多个SubSystem。每个SubSystem都不是一个单独的类,而是一个类的集合。SubSystem并不知道Facade的存在,对于SubSystem而言,Facade知识另一个客户端而已(Facade对SubSystem透明)
(2)举例:
去教室自习,第一个进教室的人儿 一般先会开前灯,再开中灯,再开后灯,这样整个教室都亮了,以便更好的进行自习;自习结束时,最后一个人儿,会先关后灯,再关中灯,再关前灯后离开。
如果设置一个总开关,来控制整个教室的灯的开关就会很方便。
在这里,总灯就是外观角色,而前中后灯都是子系统角色。
(3)优点:
①减少了系统的相互依赖,实现了客户端与子系统的耦合关系,这使得子系统的变化不会影响到调用它的客户端
②提高了灵活性,简化了客户端对子系统的使用难度,客户端无需关心子系统的具体实现方式,而只需要和面向对象交互即可
③提高了安全性,可以林火设定访问权限,不在门面对象中开通方法,就无法访问
3、日志格式的说明
①时间日期:精确到秒
②日志级别
③进程ID
④线程名
⑤Logger名(通常使用源代码的类名)
⑥日志内容
4、日志级别
4.1日志级别的分类
(1)日志级别代表日志信息对应问题的严重性,为了更快的筛选符合目标的日志信息。有了日志级别就可以过滤自己想看到的信息了,比如只关注error级别的,就可以根据级别过滤出error级别的日志信息,节约开发者的信息筛选时间
(2)日志级别的分类:
日志的级别从高到低依次为:FATAL、ERROR、WARN、INFO、DEBUG、TRACE
①FATAL:致命信息,表示需要立即被处理的系统级错误
②ERROR:错误信息,级别较高的错误日志信息,但仍然不影响系统的继续进行
③WARN:警告信息,不影响使用,是需要注意的问题
④INFO:普通信息,用于记录应用程序正常运行的一些信息,例如系统启动完成、请求处理完成等
⑤DEBUG:调试信息,需要调试时候打印关键信息
⑥TRACE:追踪信息,比DEBUG更细粒度的信息事件(除非有特殊用意,否则请使用DEBUG代替)
4.2日志级别的使用
@RequestMapping("/printLog")
public String printLog(){
logger.trace("===trace===");
logger.debug("===debug===");
logger.info("===info===");
logger.warn("===warn===");
logger.error("===error===");
return "打印不同级别的日志";
}
SpringBoot默认的日志框架是Logback,Logback没有fatal级别,它被映射到error。
观察运行结果,发现只打印了info、warn和error级别的日志,是因为日志的输出级别默认是info,所以只会打印大于等于info级别的日志,也就是info、warn、error。
5、日志配置
5.1配置日志级别
(1)Properties配置:
logger.level.root:debug
(2)yml配置:
logger:
level:
root:debug
5.2日志持久化
(1)开发环境上的日志都是输出到控制台上的,然而在线上环境中,我们需要把日志保存下来,以便出现问题之后追溯问题。把日志保存下来就叫做持久化。
(2)日志持久化的两种方式:
①配置日志文件名
Properties配置:
logger.file.name:logger/springboot.log
Yml配置:
logging:
file:
name:logger/springboot.log
[两者任选其一即可]
②配置日志的存储目录
Properties配置:
logger.file.path:D:/temp
Yml配置:
logging:
file:
path:D:/temp
[两者任选其一即可]
(3)当logger.file.name与logger.file.path两个都配置的情况下,只生效其一,以logger.file.name为准
5.3划分日志文件大小
(1)如果我们的日志都放在一个文件中,随着项目的运行,日志文件会越来越大,需要对文件进行分割。【当然日志框架也考虑到了,如果不进行配置,默认就是10M进行分割】
(2)配置日志文件的分割:
①Properties配置:
logging.logback.rollingpolicy.max-file-size: 1KB logging.logback.rollingpolicy.file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}}.%i
②yml配置:
logging: logback: rollingpolicy: max-file-size: 1KB file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}}.%i
(3)
logging.logback.rollingpolicy.file-name-pattern:日志分割后的文件名格式
logging.logback.rollingpolicy.max-file-size:日志文件超过这个大小就自动分割
5.4配置日志格式
(1)目前日志打印的格式是默认的,打印日志的格式,也是支持可配置的,支持控制台和日志文件分别设置。
(2)
logging.pattern.console:控制台日志格式
logging.pattern.file:日志文件的日志格式
①properties配置:
logging.pattern.console='%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'
②yml配置:
logging:
pattern:
console:'%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'
file:'%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'
(3)通常情况下我们使用默认的日志打印格式就足够了
6、简单化的日志输出
6.1添加lombok依赖
每次使用日志工厂创建日志对象时十分繁琐的,而且几乎每个类都需要添加一遍,lombok给我们提供了一种更简单的方式就是使用 @Slf4j 注解输出日志
6.2使用注解@Slf4j输出日志
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class LogController {
@RequestMapping("/log")
public void log(){
log.info("-----要输出日志内容-----");
}
}