SpringBoot 日志文件相关 门面模式
目录
1. 日志概念
1.1 什么是日志
1.2 日志的作用
2. 使用日志 - slf4j
2.1 日志级别
2.2 Logger
2.2.1 配置日志级别
2.3 @Slf4j
3. 门面模式
3.1 什么是门面模式
3.2 门面模式的具体应用
3.3 门面模式的优点
3.4 代码实现
4. 日志持久化
4.1 配置日志文件名
4.2 配置日志文件路径
5. 配置日志文件的分割
5.1 配置日志分割大小
5.2 配置文件分割格式
6. 配置日志打印格式
1. 日志概念
1.1 什么是日志
其实, 我们每天都在接触日志, 比如 Spring 展示在控制台的内容, 就是日志:
还有, 我们在 JavaSE 阶段, 通过 System.out.println 打印内容来进行 debug, 其中打印出的内容就是日志.
1.2 日志的作用
上文说到, 我们通过日志来发现问题, 定位问题, 解决问题, 除此之外, 日志还有其他作用:
- 系统监控 => 比如, 通过监控数据, 检测接口的响应时间, 进行数据分析等等
- 数据采集 => 比如, 购物软件, 通过日志记录了我们的浏览量和点击量, 从而推送我们感兴趣的产品, 进而促进我们消费
- 日志审计 => 日志记录了我们的浏览记录, 当我们通过网络进行一些非法操作时, 网络安全部门就会出动, 解决安全隐患.
2. 使用日志 - slf4j
当我们启动 SpringBoot 项目时, 就会有日志输入:
我们发现 , Spring 打印出的日志, 要比我们通过 System.out.println 打印的日志要详细的多.
并且, Spring 也提供了日志框架, 我们可以通过日志框架, 打印出我们想要的日志内容.
2.1 日志级别
Spring 为日志划分了级别, 日志级别代表了问题的严重程度, 级别越高, 问题就越严重.
日志级别从高到低为: FATAL、ERROR、WARN、INFO、DEBUG、TRACE
- FATAL => 致命信息, 表示需要立即被处理的系统级错误
- ERROR => 错误信息, 级别较高的错误日志信息, 但仍然不影响系统的继续运行
- WARN => 警告信息, 不影响使用, 但需要注意的问题
- INFO => 普通信息, 用于记录应用程序正常运行时的⼀些信息, 例如系统启动完成、请求处理完成等(Spring 中默认的日志级别为 INFO)
- DEBUG => 调试信息, 需要调试时的关键信息打印
- TRACE => 追踪信息, 比 DEBUG 更细粒度的信息事件(除非有特殊用意, 否则请使用 DEBUG 级别替代)
其中, Spring 默认的日志级别为 INFO, 也就是说, Spring 只会展示 INFO 及其以上级别的日志信息, DEBUG 和 TRACE 级别的日志信息默认是不会输出的. (言外之意: DEBUG, TRACE 日志记录的信息不值一提)
2.2 Logger
使用 Spring 提供的 Logger 打印日志.
首先, 通过 LoggerFactory.getLogger 获取 Logger 对象. 再通过 org.slf4j 包下的 Logger 接收.
注意, Logger 有很多路径, 选择 org.slf4j 包下的 Logger!!(原因下文讲)
接着, 就可以使用 Logger 对象来打印日志了:
方法名, 就是日志级别.
调用 Logger 对象的 info 方法, 打印出来的就是 info 级别的日志. 当然, 调用其他级别的方法, 打印出来的也是相应级别的日志:
从图中我们可以得知:
- Spring 没有提供 fatal 级别日志方法 (如果真的出现 fatal 级别的问题, 那也用不着日志提醒了, 客服手机就打到爆了)
- Spring 默认的日志级别是 INFO, 不会打印 INFO 以下级别的日志信息
2.2.1 配置日志级别
上文说到, 由于 Spring 默认的日志级别是 INFO, 所以不会输出 INFO 以下级别的日志.
其实, 我们可以在配置文件中修改 Spring 默认的日志级别, 来展示 DEBUG/TRACE 日志:
# 将默认的日志级别修改为 TRACE
logging:
level:
root: trace
修改后, 就可以观察到我们所写的日志信息:
观察控制面板, 我们发现, 不仅我们手动写的日志被打印了, 而且还输入了一堆 Spring 自身 TRACE/DEBUG 级别的日志信息, 并且不断在增加:
因为, 在修改默认日志级别时, 我们是将 root(根目录) 即所有路径下的默认日志级别都修改成了 TRACE, 因此, 所有包(包括 Spring 自身)的日志信息都被打印了.
因此, 我们可以将指定包的日志级别单独进行修改:
2.3 @Slf4j
使用日志框架打印日志, 除了上文使用 LoggerFactory.getLogger 获取 Logger 对象外, 还有一种更方便的方法供我们使用日志框架, 就是使用 @Slf4j 注解. (@Slf4j 是 lombok 框架提供的注解)
@Slf4j 注解, 可以帮助我们自动生成 Logger 对象, 对象名为 log, 我们可以直接使用 log 调用日志打印的方法:
我们也可以将源代码和反编译后的代码进行对比:
观察可知, @Slf4j 的确帮我们自动生成了 Logger 对象, 我们直接使用即可.
3. 门面模式
3.1 什么是门面模式
门面模式, 也称为外观模式, 是设计模式的一种. 它提供了一个统一的接口, 用于访问子系统中的一组接口.
门面模式中有两个重要角色:
- 门面/外观角色(Facade): 提供一个简化的、统一的接口, 供客户端使用, 隐藏子系统内部的复杂性(只提供接口, 不进行实现, 具体实现委托给子系统, 但客户端只需调用门面角色即可)
- 子系统角色(SubSystem): 实现具体的功能(通常有多个)
也就是说, 门面模式提供了一个更简单、更高级别的接口, 隐藏底层系统(子系统)的复杂性, 从而使客户端更容易使用.
举个例子, 假如我家中有好几台不同品牌的电视, 那我想看电视时, 就可以使用一个通用遥控器对所有的电视进行操作, 而不用关注电视本身配置的遥控器是什么了.
此时, 这个通用遥控器就是门面.
而 不同的电视, 就是子系统.
3.2 门面模式的具体应用
在上文中, 我们使用的 slf4j 就是典型的门面模式的应用.
使用 Logger 对象时, 我们就发现了有很多包都提供了 Logger 类, 而我们只需选择 slf4j 即可, 因为 slf4j 就是刚才所说的 "门面角色", 而其他的 Logger 类则是 "子系统角色".
同样, SLF4J 只提供了一组接口 (info/debug/warn/....), 并没有提供具体的日志记录实现. 具体的实现是由底层的日志框架(例如 Logback, Log4j 2, java.util.logging)提供的.
我们只需通过 SLF4J 完成统一的日志操作, 而无需关心底层具体的日志框架, 这是 SLF4J 门面角色的核心的价值所在.
客户端调用 slf4j 中 Logger 的接口(info 等日志输出接口), slf4j 再调用具体日志框架(如 Logback, Log4j 2, java.util.logging)中的接口, 客户端就可以通过 slf4j 完成统一的日志输出操作, 而不必在意底层的日志框架. 因此, 实现了客户端和日志框架之间的解耦.
为什么要使用 slf4j 呢??
若不引入 slf4j, 那么一个程序中, 可能使用了多个不同的日志框架(logging, jul, logback), 那么此时就可能会出现框架冲突的情况.
而引入门面模式, 我们只需调用 slf4j 即可, 由 slf4j 统一进行日志框架的调用.
3.3 门面模式的优点
-
简化复杂系统:
-
门面模式提供了一个更简单、更高级别的接口,隐藏了子系统内部的复杂性。 客户端无需了解子系统中各个组件的细节,只需与门面交互即可。
-
降低了客户端的学习成本和使用难度。
-
-
降低耦合度:
-
门面模式将客户端与子系统解耦。 客户端不再直接依赖于子系统内部的组件,而是通过门面进行交互。
-
提高了代码的可维护性和可重用性。
-
-
提高灵活性:
-
门面模式允许你修改子系统的内部实现,而不会影响客户端代码。 只要门面的接口保持不变,客户端代码就可以继续正常工作。
-
更容易进行系统升级和扩展。
-
3.4 代码实现
注意: 这里只是展示一种门面模式的实现, 门面模式的实现有很多种!!
设计模式重思想, 轻代码!!
场景如下:
回到家中, 我要打开家中的灯, 客厅灯, 走廊灯, 卧室灯, 都要打开; 工作走时, 我需要关闭家中所有灯, 客厅灯, 走廊灯, 卧室灯, 都要关闭.
那么, 我们就可以通过门面(如智能家居), 统一完成灯的开和关, 简化操作.
-
子系统 (Subsystem): 客厅灯、走廊灯、卧室灯 可以看作是三个独立的子系统, 每个灯都有自己的开关方法.
-
复杂性: 如果每次回家或离开都要手动打开/关闭每个灯, 操作繁琐.
-
门面 (Facade): 可以创建一个 "智能家居控制面板" 或 "灯光控制系统" 作为门面.
public interface Light {
void on();
void off();
}
public class LivingRoomLight implements Light{
@Override
public void on() {
System.out.println("打开客厅灯");
}
@Override
public void off() {
System.out.println("关闭客厅灯");
}
}
public class BedRoomLight implements Light{
@Override
public void on() {
System.out.println("打开卧室灯");
}
@Override
public void off() {
System.out.println("关闭卧室灯");
}
}
public class HallLight implements Light{
@Override
public void on() {
System.out.println("打开走廊灯");
}
@Override
public void off() {
System.out.println("关闭走廊灯");
}
}
// 门面角色
public class FacadeClient {
BedRoomLight bedRoomLight = new BedRoomLight();
LivingRoomLight livingRoomLight = new LivingRoomLight();
HallLight hallLight = new HallLight();
public void on() {
bedRoomLight.on();
livingRoomLight.on();
hallLight.on();
}
public void off() {
bedRoomLight.off();
livingRoomLight.off();
hallLight.off();
}
}
public class Main {
// 通过门面, 统一进行开关灯
public static void main(String[] args) {
FacadeClient facadeClient = new FacadeClient();
facadeClient.on();
facadeClient.off();
}
}
4. 日志持久化
上文的日志都是展示在控制台上的, 项目每重启一次日志就消失了. 而在实际工作中, 我们需要将日志持久化保存起来.
日志持久化有两种方式:
- 配置日志文件名 => logging.file.name
- 配置日志目录 => logging.file.path
logging.file.name | Log file name (for instance, `myapp.log`). Names can be an exact location or relative to the current directory. |
Location of the log file. For instance, `/var/log`. |
(取自 Spring 官方
Common Application Properties :: Spring Boot)
以上两种方式都是在配置文件(Properties/yml)中进行设置的.
4.1 配置日志文件名
logging.file.name 不仅可以配置日志文件名, 还可以配置日志文件的相对路径和绝对路径:
4.2 配置日志文件路径
logging.file.path 配置文件路径.
注意: logging.file.path 只能配置文件路径, 不能配置文件名, 文件名只能是 spring.log. 也就是说, 在 logging.file.path 中配置的信息都是 "文件夹" 的名称, 真正存放日志的文件是 spring.log.
注意:
当 logging.file.name 和 logging.file.path 都同时存在时, 那么以 logging.file.name 为准.
(logging.file.name 的优先级更高)
5. 配置日志文件的分割
在实际工作中, 随着项目的运行, 日志文件会越来越大, 那么就需要对日志文件进行分割.
(Spring 中, 默认的文件分割大小为 10MB)
logging.logback.rollingpolicy.file-name-pattern | Pattern for rolled-over log file names.(分割后的日志文件名格式) |
|
Maximum log file size. (日志超过这个大小就自动分割) |
|
5.1 配置日志分割大小
logging.logback.rollingpolicy.max-file-size
Spring 中, 默认的日志分割大小为 10MB, 当日志文件超过 10MB 时, 就会自动分割.
在企业中, 日志分割通常设置为 200MB - 1G 之间.(不同企业有不同的标准)
5.2 配置文件分割格式
logging.logback.rollingpolicy.file-name-pattern
默认分割后的文件格式为 ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz
.gz 为压缩文件, 查看日志时需要进行解压处理, 比较麻烦. 为了方便直接在 IDEA 上查看日志文件, 我们可以自定义分割后的日志文件的格式/名称.
6. 配置日志打印格式
目前, 我们 IDEA 中, 日志输入的格式是默认的:
我们同样也可以通过配置文件自定义文件格式:
logging.pattern.console | Appender pattern for output to the console. Its default value varies according to the logging system. |
logging.pattern.file | Appender pattern for output to a file. Its default value varies according to the logging system. |
由于目前默认的日志格式就已经非常好用了, 自定义格式就不再演示.
END