SpringBoot 日志

1. 日志框架

Java常见的日志框架:

  • SLF4J:日志门面,不直接实现日志,推荐业务代码使用。
  • Logback:Spring Boot 默认日志实现,配置简单。
  • Log4j2:高性能,支持异步日志、结构化日志。
  • JUL / JCL:较老,通常不直接用于新项目。

SLF4J不同于其他日志框架, 它不是⼀个真正的日志实现, 而是⼀个抽象层, 对日志框架制定的⼀种规范, 标准, 接口. 所有SLF4J并不能独立使用, 需要和具体的日志框架配合使用。

SLF4J 就像通用遥控器,而 log4j2 、 Logback 和 JUL 就像不同品牌的电视机,通过 通用的遥控器 可以操作不同品牌的电视。

门面模式(外观模式)

SLF4J是门面模式的典型应用(但不仅仅使用了门面模式).

门面模式(Facade Pattern)又称为外观模式, 提供了⼀个统⼀的接⼝, 用来访问子系统中的⼀群接⼝。 其主要特征是定义了⼀个高层接口, 让子系统更容易使用。

门面模式主要包含2种角色:

外观角色(Facade):也称门面角色,系统对外的统一接口。

子系统角色 (SubSystem):可以同时有一个或多个SubSystem.每个SubSytem都不是一个单独的类,

而是一个类的集合.SubSystem并不知道Facade的存在,对于SubSystem而言,Facade只是另一个客户端而已(即 Facade 对 SubSystem透明)


门面模式的实现

场景: 回家, 我们会开各个屋的灯. 离开家时, 会关闭各个屋的灯

如果家里设置⼀个总开关来控制整个屋的灯就会很方便

我们使用门面模式的实现:

门面模式的优点:

  • 减少了系统的相互依赖,实现了客户端与子系统的耦合关系,这使得子系统的变化不会影响到调用它的客户端;
  • 提高了灵活性,简化了客户端对子系统的使用难度,客户端无需关心子系统的具体实现方式,而只需要和门面对象交互即可.
  • 提高了安全性,可以灵活设定访问权限,不在门面对象中开通方法,就无法访问

SLF4J 框架介绍

SLF4J就是其他日志框架的门面.SLF4J可以理解为是提供日志服务的统一API接口,并不涉及到具体的日志逻辑实现.

不引入日志门面

常见的日志框架有log4J,logback等.如果一个项目已经使用了log4j,而你依赖的另一个类库,假如是Apache Active MQ,它依赖于另外一个日志框架logback,那么你就需要把logback也加载进去.

存在问题:

  • 1.不同日志框架的API接口和配置文件不同,如果多个日志框架共存,那么不得不维护多套配置文件(这个配置文件是指用户自定义的配置文件).
  • 2.如果要更换日志框架,应用程序将不得不修改代码,并且修改过程中可能会存在一些代码冲突。
  • 3.如果引入的第三方框架,使用了多套,那就不得不维护多套配置。

引入日志门面

引入门面日志框架之后,应用程序和日志框架(框架的具体实现)之间有了统一的API接口(门面日志框架实现),此时应用程序只需要维护一套日志文件配置,且当底层实现框架改变时,也不需要更改应用程序代码.

SLF4J就是这个日志门面。

总的来说,SLF4J使你的代码独立于任意一个特定的日志API,这是一个对于开发API的开发者很好的思想。

2. 日志的使用

Spring Boot 项目在启动的时候默认就有日志输出,如下图所示:

它打印的日志和 System.out.print 有什么不同呢:

访问 http://127.0.0.1:8080/logger/print,观察日志输出:

可以看到, 我们通过 System.out.print 打印的日志, 比SpringBoot 打印的日志缺少了很多信息。

① 日志格式说明

SpringBoot 日志输出内容元素具体如下:

从上图可以看到,日志输出内容元素具体如下:

  1. 时间日期:精确到毫秒
  2. 日志级别:ERROR, WARN, INFO, DEBUG 或 TRACE
  3. 进程ID
  4. 线程名
  5. Logger名(通常使用源代码的类名)
  6. 日志内容

其中,应用名称是根据 配置文件 中是否有配置而定的:

如果未配置,则不显示:

② 打印日志

SpringBoot 内置了日志框架 Slf4j , 我们可以直接在程序中调用 Slf4j 来输出日志。

打印日志的步骤:

  • 在程序中得到日志对象.
  • 使用日志对象输出要打印的内容

使用 org.slf4j 包下的 Logger 类,在程序中获取日志对象需要使用日志工厂LoggerFactory 的 getLogger 方法,如下代码所示:

使用上述的日志对象打印日志:

打印日志效果展示:

③ 日志的级别

日志的级别从高到低依次为: FATAL、ERROR、WARN、INFO、DEBUG、TRACE

  • FATAL: 致命信息,表示需要立即被处理的系统级错误
  • ERROR: 错误信息, 级别较高的错误日志信息, 但仍然不影响系统的继续运行.
  • WARN: 警告信息, 不影响使用, 但需要注意的问题
  • INFO: 普通信息, 用于记录应⽤程序正常运行时的⼀些信息, 例如系统启动完成、请求处理完成等.
  • DEBUG: 调试信息, 需要调试时候的关键信息打印.
  • TRACE: 追踪信息, 比DEBUG更细粒度的信息事件(除非有特殊用意,否则请使用DEBUG级别替代)

级别越高,收到的消息越少。

日志级别的使用

日志级别是开发人员自己设置的,开发人员根据自己的理解来判断该信息的重要程度

针对这些级别, Logger 对象分别提供了对应的方法, 来输出日志:

访问http://127.0.0.1:8080/logger/printLog,观察日志信息:

结果发现, 只打印了info, warn和error级别的日志

这与日志级别的配置有关,日志的输出级别默认是 info级别 , 所以只会打印大于等于此级别的日志, 也就是info, warn和error。

④ 日志配置

上述是日志的使用, 日志框架支持我们更灵活的输出日志, 包括内容, 格式等

配置日志级别

日志级别配置只需要在配置文件中设置 "logging.level" 配置项即可,如下所示:

重新运行上述代码:

⑤ 日志持久化

以上的日志都是输出在控制台上的, 下一次运行时,之前的日志都会消失,然而在线上环境中, 我们需要把日志保存下来, 以便出现问题之后追溯问题. 把日志保存下来就叫持久化。

日志持久化有两种方式:

  1. 配置日志文件名
  2. 配置日志的存储目录

logging.file.name 控制完整的文件名(可包含路径),即指定日志文件的完整名称或完整路径

  • 用法:
  • 只写文件名(如 myapp.log):日志会生成在当前项目的当前工作目录下,文件名为 myapp.log。
  • 写绝对路径(如 /var/log/myapp.log 或 D:/logs/myapp.log):日志会精确生成在指定的位置,并使用指定的文件名。
  • 特点:灵活性最高,你可以完全自定义日志叫什么名字,放在哪里。

logging.file.path 只控制存储目录,文件名由框架默认生成(spring.log)。

  • 默认行为:如果你配置了 logging.file.path=/var/log,但没有配置 logging.file.name,Spring Boot 会在这个目录下自动创建一个默认文件名的日志文件,默认名字通常是 spring.log。
  • 特点:你只关心日志放在哪个文件夹,不关心它叫什么名字。

配置日志文件的路径和文件名:

重新运行,右击项目点击刷新:

运行结果显示, 日志内容保存在了对应的目录下:

该日志中也保存了刚才运行后的结果日志:

再次运行,除了保存之前的日志,还新添加了刚才运行的:

这样就实现了日志的持久化。


配置日志文件的保存路径:

此时我们设置和 file.name 一样的路径:

看看运行后 log.log 是不是日志文件:

如上图所示,只是一个单纯的路径而已,file.path 文件名是默认的 spring.log。

注意 : logging.file.name 和 logging.file.path 两个都配置的情况下, 只生效其⼀,以 logging.file.name 为准。

例如,此时配置了两个日志文件:

运行刷新后,确实是以 file.name 为准:

⑥ 配置日志文件分割

如果我们的日志都放在⼀个文件中, 随着项目的运行, 日志文件会越来越大,需要对日志文件进行分割。

|-------------------------------------------------|-----------------|----------------------------------|
| 配置项 | 说明 | 默认值 |
| logging.logback.rollingpolicy.file-name-pattern | 日志分割后的文件格式 | ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz |
| logging.logback.rollingpolicy.max-file-size | 日志文件超过这个大小就自动分割 | 10MB |

配置日志文件分割:

日志分割的结果:

可以看出这些日志文件是压缩文件。

设置一下文件格式,注意到 默认值是 ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz,我们可以把 .gz 的后缀去掉,这样就是一个可以随时打开的普通文件了。

再次运行,观察日志文件分割:

此时都是一些普通文件,一个文件大小是 1KB,也就是 1KB 就分割。

分割后的日志文件名为:日志名( ${LOG_FILE}).日期( %d{yyyy-MM-dd}).索引( %i.)

⑦ 配置日志格式

目前日志打印的格式是默认的

打印日志格式, 也是支持配置的,支持控制台和日志文件分别设置

|-------------------------|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 配置项 | 说明 | 默认值 |
| logging.pattern.console | 控制台日志格式 | %clr(%d{{LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}}){faint} %clr({LOG_LEVEL_PATTERN:-%5p}) %clr({PID:- }){magenta} %clr(---){faint} %clr(\[%15.15t\]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n{LOG_EXCEPTION_CONVERSION_WORD:-%wEx} |
| logging.pattern.file | 日志文件的日志格式 | %d{{LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}} {LOG_LEVEL_PATTERN:-%5p} {PID:- } --- \[%t\] %-40.40logger{39} : %m%n{LOG_EXCEPTION_CONVERSION_WORD:-%wEx} |

设置控制台日志格式:

观察日志变化:

3. 简单日志输出

每次都使用 LoggerFactory.getLogger(xxx.class) 很繁琐, 且每个类都添加⼀遍, lombok给我们提供了一种更简单的方式。

  1. 添加 lombok 框架支持
  2. 使用 @slf4j 注解输出日志

添加Lombok依赖:

输出日志:

lombok提供的 @Slf4j 会帮我们提供⼀个日志对象 log, 我们直接使用就可以.

也就是说

复制代码
@Slf4j   等于 
private static Logger logger = LoggerFactory.getLogger(LoggerController.class);
相关推荐
hai_android1 小时前
Android JNI 示例详解:Java 与 C++ 互调演示
android·java
小白说大模型1 小时前
《FDE前沿部署工程师实战教程》企业 Agent 项目实战:从需求分析到 PoC 落地
人工智能·spring·机器学习·自然语言处理·chatgpt·数据挖掘·需求分析
geovindu1 小时前
java: Strategy Pattern
java·开发语言·后端·设计模式·策略模式·行为模式
yimindev1 小时前
从 BI 到 Agent:我如何用 Java 打造一个轻量级数据库语义网关 DatI
java
计算机毕设定制辅导-无忧学长1 小时前
《基于SpringBoot的家政服务管理平台的设计与实现》
java·vue.js·spring boot·计算机毕业设计选题推荐·家政服务管理平台
秋饼1 小时前
Spring AI 2.0 企业级文档ETL实战:从 DocumentReader 到 EmbeddingStore 的完整知识库数据管道
java·ai·技术分享·后端开发
吃饱了得干活1 小时前
Spring Boot + Redis 分布式锁:一个订单重复提交引发的六次迭代
java·redis·后端
xiaoqiMikko1 小时前
pom 里没有、代码里没调过,但 WebClient 默认用的就是 netty-resolver-dns
java·spring boot
wuminyu1 小时前
Kafka的写入延迟与磁盘IO抖动原理分析
java·linux·c语言·jvm·c++