目录
1.前言
哈喽大家好啊,今天来给大家分享的是Spring开发中日志的使用。日志在软件开发中扮演着至关重要的角色,它就像是系统运行的 “黑匣子”,记录着程序执行过程中的各种信息,帮助我们定位问题、分析系统状态,对于 Spring 开发而言,掌握日志的使用更是开发过程中的必备技能,下面我将详细为大家讲解 Spring 日志的相关内容。
2.日志使用
这里给大家提供一个日志在一个应用场景的使用:
2.1 打印日志
这是启动Spring程序时就有的日志:
2.1.1 在程序中得到日志对象
在 Spring 中,要想使用日志功能,首先得获取日志对象。一般我们会借助日志框架提供的工厂类来获取。例如,使用commons-logging框架时,可以通过LogFactory来获取日志对象:
Log log = LogFactory.getLog(YourClass.class);
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OrderService {
// 通过类名初始化日志对象
private static final Logger logger =
LoggerFactory.getLogger(OrderService.class);
}
这种方式也是比较常见的,LoggerFactory作为日志工厂,能够根据配置为我们创建相应的日志记录器,与具体的日志实现框架相配合,实现日志功能。
2.1.2 使用日志对象打印日志
为了方便调试,我们这里编写了这样一段程序:
package springlog.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/log")
@RestController
public class LogController {
private static Logger logger = LoggerFactory.getLogger(LogController.class);
@RequestMapping("/print")
public String print(){
System.out.println("sout打印日志");
logger.info("logger打印日志");
// logger.trace("trace");
// logger.debug("debug");
// logger.warn("warn");
// logger.debug("debug");
// logger.error("error");
return "打印日志";
}
}
运行起来程序,访问本地的8080端口号下的/log/print :
再回去看日志:
可以看到日志已被打出。
2.2 日志框架介绍(了解)
2.2.1 门面模式(外观模式)
门面模式(Facade Pattern)是一种 结构型设计模式,主要用于简化复杂系统的调用方式。这里用一部分代码来解释门面模式:
核心思想:
提供一个统一的高层接口,隐藏子系统的复杂性,使客户端只需与门面交互,而无需直接调用多个底层组件。
类比现实:就像电灯的 总开关,按一次就能控制所有灯(无需逐个操作卧室、客厅、走廊的灯)。
核心代码:
package springlog.facade; public interface Light { void on(); void off(); }
package springlog.facade; public class FacadeClient{ private LivingRoomLight livingRoomLight = new LivingRoomLight(); private BedroomLight bedroomLight = new BedroomLight(); private HallLight hallLight = new HallLight(); public void on() { livingRoomLight.on();; bedroomLight.on(); hallLight.on(); } public void off() { livingRoomLight.off(); bedroomLight.off(); hallLight.off(); } }
package springlog.facade; public class Main { public static void main(String[] args) { FacadeClient facadeClient = new FacadeClient(); facadeClient.on(); facadeClient.off(); } }
角色 对应代码 作用 子系统(Subsystem) BedroomLight
、LivingRoomLight
、HallLight
实际执行业务的底层组件(如具体的灯) 门面(Facade) FacadeClient
聚合子系统功能,提供简化的接口(如 on()
/off()
一键操作所有灯)客户端(Client) Main
类只依赖门面,不直接操作子系统
关键设计要点:
(1) 简化接口
门面类
FacadeClient
将多个灯的开关操作封装成两个方法:public void on() { livingRoomLight.on(); bedroomLight.on(); hallLight.on(); }
客户端只需调用
facadeClient.on()
,无需关心具体哪些灯被打开。(2) 解耦客户端与子系统
客户端(
Main
)仅依赖FacadeClient
,不直接操作Light
的实现类。如果未来灯的类需要修改(例如替换为智能灯泡),只需调整
FacadeClient
,客户端代码无需变动。(3) 符合迪米特法则(最少知识原则)
客户端不需要知道子系统内部的复杂关系(如灯的依赖、初始化顺序等),只需通过门面交互。
门面模式的优点:
优点 在本例中的体现 降低复杂度 客户端无需分别操作三个灯,只需调用门面的 on()
/off()
提高可维护性 修改子系统(如增加新灯)时,只需调整门面类,不影响客户端 减少耦合 客户端代码不依赖具体灯的实现类,仅依赖门面 易于扩展 新增子系统组件(如厨房灯)时,只需在门面中整合,无需修改现有客户端逻辑
门面模式通过 封装复杂细节、提供简洁接口,实现了客户端与子系统的解耦。在需要统一管理多个关联组件时(如智能家居控制、多层系统调用),它能显著提升代码的可维护性和易用性。
2.2.2 SLF4]框架介绍
SLF4J(Simple Logging Facade for Java) 是 Java 的一个 日志门面框架(日志抽象层),它本身不提供日志实现,而是提供统一的 API,允许开发者自由选择底层日志框架(如 Logback、Log4j2、JUL 等)。
特性 | 说明 |
---|---|
门面模式(Facade) | 提供统一的日志接口,不依赖具体实现(类似 JDBC 驱动与数据库的关系) |
兼容多种日志实现 | 支持 Logback、Log4j2、Java Util Logging(JUL)等作为底层实现 |
占位符({})功能 | 使用 logger.info("User: {}, Age: {}", name, age) 避免字符串拼接,提高性能 |
优势有哪些:
✅ 解耦:代码只依赖 SLF4J API,更换日志实现无需修改业务代码。
✅ 性能优化:{}
占位符比字符串拼接更高效(避免无效的String
操作)。
✅ 灵活性:可自由切换日志实现,适应不同环境(如测试用 Logback,生产用 Log4j2)。
✅ 兼容性:解决 Java 生态中多种日志框架并存的问题(如 Hibernate 用 JBoss Logging,Spring 用 Commons Logging)。
2.3 日志格式的说明
2023-08-20 14:22:45.678 INFO 25484 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http)
各字段含义:
日期时间:精确到毫秒
日志级别:此处为INFO
进程ID
线程名([main]表示主线程)
Logger名称(通常为类名)
日志消息
时间 + 日志级别 + 进程ID + 应用名称 + 线程名称 + 类的路径 + 日志内容
2.4 日志级别
2.4.1 日志级别的分类
日志的级别从高到低依次为:FATAL、ERROR、WARN、INFO、DEBUG、TRACE
- - FATAL:致命信息,表示需要立即被处理的系统级错误。
- - ERROR:错误信息,级别较高的错误日志信息,但仍然不影响系统的继续运行。
- - WARN:警告信息,不影响使用,但需要注意的问题。
- - INFO:普通信息,用于记录应用程序正常运行时的一些信息,例如系统启动完成、请求处理完成等。
- - DEBUG:调试信息,需要调试时候的关键信息打印。
- - TRACE:追踪信息,比DEBUG更细粒度的信息事件(除非有特殊用意,否则请使用DEBUG级别替代)
2.4.2 日志级别的使用
测试代码:
package springlog.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/log")
@RestController
public class LogController {
private static Logger logger = LoggerFactory.getLogger(LogController.class);
@RequestMapping("/print")
public String print(){
System.out.println("sout打印日志");
logger.info("logger打印日志");
logger.trace("trace");
logger.debug("debug");
logger.warn("warn");
logger.debug("debug");
logger.error("error");
return "打印日志";
}
}
在实际开发中,我们需要根据不同的场景合理选择日志级别。在开发阶段,可以适当使用debug和trace级别来获取详细的调试信息,帮助我们快速定位问题。而在生产环境中,为了减少日志对系统性能的影响,通常会将日志级别设置为info或warn及以上。例如,对于一些关键业务逻辑的正常执行情况使用info级别记录,对于可能出现的潜在问题使用warn级别提醒,而对于程序中的错误则使用error级别进行详细记录。同时,我们还可以通过配置文件动态地调整日志级别,以便在不同的运行阶段灵活地控制日志的输出量和详细程度。
2.5 日志配置
2.5.1 配置日志级别
在yml配置文件中设置日志类型:
logging:
level:
root: info
main:
java:
springlog:
controller: trace
我们可以看到,切换后日志就与之前不一样了。
2.5.2 日志持久化
为什么要做日志持久化?
三大关键要点:
故障追溯:保留完整的系统运行记录
性能分析:通过历史日志分析系统瓶颈
安全审计:满足等保合规要求
配置yml文件,启动项目后刷新:
logging:
# level:
# root: info
# main:
# java:
# springlog:
# controller: trace
file:
name: log/log.log
可以看到日志被放在包中的一个文件中。
如果采用相对路径配置:
file:
path: logger/
logging.file,path 设置日志的路径。
logging.file.name 设置日志的名称,可以带绝对路径或者相对路径。
如果两个配置,同时存在,以 logging.file.name为主(即优先级高)
properties配置格式:
# 指定完整日志路径(优先使用)
logging.file.name=/var/log/myapp/application.log
# 或指定目录(生成spring.log)
logging.file.path=/var/log/myapp
2.5.3 配置日志文件分制
如果我们把日志都放在一个文件中,随着项目的运行,日志文件会越来越大,所以需要对日志文件进行分割。
logging:
logback:
rollingpolicy:
# 单个日志文件最大体积(支持KB/MB/GB单位)
max-file-size: 100MB
# 保留历史日志天数(滚动删除)
max-history: 30
# 总日志容量上限
total-size-cap: 10GB
# 文件名模式(时间+序号)
file-name-pattern: "${LOG_FILE}.%d{yyyy-MM-dd}.%i.log"
参数 | 说明 | 生产环境推荐值 |
---|---|---|
max-file-size | 触发分割的单个文件大小 | 100-500MB |
max-history | 保留旧日志文件天数 | 15-60天 |
total-size-cap | 日志文件总量限制 | 磁盘空间的70% |
file-name-pattern | 滚动文件命名规则 | 必须包含%d(日期)和%i(序号) |
2.5.4 配置日志格式
logging:
pattern:
# 控制台格式(带ANSI颜色)
console: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){cyan} %clr(%-5level){magenta} %clr(%logger{35}){blue} - %msg%n"
# 文件格式(结构化)
file: "%d{ISO8601}|%thread|%-5level|%logger{35}|%msg%n"
格式符号速查表
占位符 | 说明 | 示例 |
---|---|---|
%d | 日期时间 | %d{yyyy-MM-dd HH:mm:ss} |
%thread | 线程名 | main |
%-5level | 左对齐日志级别 | INFO |
%logger{length} | 类名缩写 | c.e.s.UserService |
%msg | 日志消息 | User login success |
%n | 换行符 | |
%X{key} | MDC上下文值 | %X{traceId} |
%clr() | ANSI颜色块 | %clr(INFO){blue} |
3.更简单的日志输出
在开发过程中,为了简化日志输出代码,提高开发效率,我们可以借助 Lombok 提供的日志注解功能。通过添加 Lombok 依赖并使用相应的注解,能够自动生成日志记录器代码,从而减少模板化代码的编写。
3.1 添加 lombok 依赖
在maven中添加Lombok依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
3.2 输出日志
引入 Lombok 依赖后,可以通过在类上添加特定的注解来自动生成日志记录器对象。最常用的就是这个:
@Slf4j
功能就相当于:
private static Logger logger = LoggerFactory.getLogger(LogController.class);
测试代码:
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class LogController {
public void log(){
log.info("--------------要输出⽇志的内容----------------");
}
}
4.总结
今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,需要所有的源代码可以去我的gitee上就可以啦~你的支持就是对我最大的鼓励,大家加油!
另外最后的最后,欢迎大家加入我的社区哦,初创社区难免经验不足,请大家多多包涵,也欢迎大家前来多多交流。