
日志的用途:
日志主要是为了发现问题、分析问题、定位问题的,但除此之外,日志还有很多用途:
Spring Boot 项目在启动的时候默认就有日志输出。
与 System.out.print 的区别
@RestController
public class LoggerController {
@RequestMapping("/logger")
public String logger() {
System.out.println("打印日志");
return "打印日志";
}
}观察日志输出:

可以看到,通过 System.out.print 打印的日志,比 Spring Boot 打印的日志缺少了很多信息。
Spring Boot 内置了日志框架 Slf4j,我们可以直接在程序中调用 Slf4j 来输出日志。
打印日志的步骤:
示例:
LoggerFactory,如下代码所示:private static Logger logger = LoggerFactory.getLogger(LoggerController.class);LoggerFactory.getLogger 需要传递一个参数,标识这个日志的名称。这样可以更清晰的知道是哪个类输出的日志。当有问题时,可以更方便直观的定位到问题类。
注意: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 {
private static Logger logger = LoggerFactory.getLogger(LoggerController.class);
}info() 方法来输出日志,如下代码所示: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 {
private static Logger logger = LoggerFactory.getLogger(LoggerController.class);
@RequestMapping("/logger")
public String logger() {
logger.info("打印日志");
return "打印日志";
}
}打印日志效果展示:

分类 | 框架 |
|---|---|
日志门面(Logging Facade) | commons-logging、SLF4J |
日志实现 | log4j 1/2、JUL、logback |
SLF4J 不同于其他日志框架,它不是一个真正的日志实现,而是一个抽象层,对日志框架制定的一种规范、标准、接口。所有 SLF4J 并不能独立使用,需要和具体的日志框架配合使用。
SLF4J 是门面模式的典型应用(但不仅仅使用了门面模式)。
门面模式定义:提供了一个统一的接口,用来访问子系统中的一群接口。其主要特征是定义了一个高层接口,让子系统更容易使用。
门面模式主要包含 2 种角色:
门面模式的实现:
场景:回家,我们会开各个屋的灯。离开家时,会关闭各个屋的灯。如果家里设置一个总开关,来控制整个屋的灯就会很方便。
public class FacadePatternDemo {
public static void main(String[] args) {
LightFacade lightFacade = new LightFacade();
lightFacade.lightOn();
lightFacade.lightOff();
}
}
/**
* 灯的门面
*/
class LightFacade {
private Light livingRoomLight = new LivingRoomLight();
private Light hallLight = new HallLight();
private Light 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("关闭餐厅灯");
}
}门面模式的优点:
SLF4J 就是其他日志框架的门面。SLF4J 可以理解为是提供日志服务的统一 API 接口,并不涉及到具体的日志逻辑实现。
引入日志门面的优势:
引入门面日志框架之后,应用程序和日志框架(框架的具体实现)之间有了统一的 API 接口(门面日志框架实现),此时应用程序只需要维护一套日志文件配置,且当底层实现框架改变时,也不需要更改应用程序代码。
打印的日志内容元素具体如下:
示例日志解析:

日志级别代表着日志信息对应问题的严重性,为了更快的筛选符合目标的日志信息。
日志的级别从高到低依次为:FATAL、ERROR、WARN、INFO、DEBUG、TRACE
日志级别顺序(从高到低):

级别越高,收到的消息越少。
针对这些级别,Logger 对象分别提供了对应的方法,来输出日志。
@RestController
@RequestMapping("/logger")
public class LoggerController {
private static final Logger logger = LoggerFactory.getLogger(LoggerController.class);
@RequestMapping("/print")
public String print(){
logger.error("打印 error 日志");
logger.warn("打印 warn 日志");
logger.info("打印 info 日志");
logger.debug("打印 debug 日志");
logger.trace("打印 trace 日志");
return "日志打印成功";
}
}默认日志级别输出结果:

结果发现,只打印了 info、warn 和 error 级别的日志。这与日志级别的配置有关,日志的输出级别默认是 info 级别,所以只会打印大于等于此级别的日志,也就是 info、warn 和 error。
日志框架支持我们更灵活的输出日志,包括内容、格式等。
日志级别配置只需要在配置文件中设置 logging.level 配置项即可。
Properties 配置:
logging.level.root=debugyml 配置:
logging:
level:
root: trace重新运行代码,观察结果:

以上的日志都是输出在控制台上的,然而在线上环境中,我们需要把日志保存下来,以便出现问题之后追溯问题。把日志保存下来就叫持久化。
日志持久化有两种方式:
配置项 | 说明 |
|---|---|
logging.file.name | 日志文件名(例如 ‘myapp.log’)。名称可以是确切位置或相对于当前目录。 |
logging.file.path | 日志文件的位置。例如 /var/log |
配置日志文件的路径和文件名:
logging.file.name=logger/springboot.loglogging:
file:
name: logger/springboot.log后面可以跟绝对路径或者相对路径。

运行结果显示,日志内容保存在了对应的目录下。
配置日志文件的保存路径:
logging.file.path=D:/templogging:
file:
path: D:/temp这种方式只能设置日志的路径,文件名为固定的 spring.log。
注意:logging.file.name 和 logging.file.path 两个都配置的情况下,只生效其一,以 logging.file.name 为准。
如果我们的日志都放在一个文件中,随着项目的运行,日志文件会越来越大,需要对日志文件进行分割。当然,日志框架考虑到了这一点,所以如果不进行配置,就走自动配置。默认日志文件超过 10M 就进行分割。
配置项 | 说明 | 默认值 |
|---|---|---|
logging.logback.rollingpolicy.file-name-pattern | 日志分割后的文件名格式 | ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz |
logging.logback.rollingpolicy.max-file-size | 日志文件超过这个大小就自动分割 | 10MB |
配置日志文件分割:
logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}.%d{yyyy-MM-dd}.%i
logging.logback.rollingpolicy.max-file-size=1KBlogging:
logback:
rollingpolicy:
max-file-size: 1KB
file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i每次都使用 LoggerFactory.getLogger(xxx.class) 很繁琐,且每个类都添加一遍,lombok 给我们提供了一种更简单的方式。
lombok 提供的 @Slf4j 注解会帮我们提供一个日志对象 log,我们直接使用就可以。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class LogController {
public void log() {
log.info("要输出日志的内容");
}
}@Slf4j 注解和 log 对象快速的打印自定义日志。