在一个项目中,日志是一个必不可少的组件。日志能帮助开发人员更好的调试程序,可以帮助运维人员查看的当前应用运行的状态。而在我们的Spring Boot
的应用中默认使用的是Logback
,Logback是log4j
框架的作者开发的新一代日志框架,它效率更高、能够适应诸多的运行环境。因为是一个作者,所以更好的支持SLF4J
。日志可以通过配置使用控制台或者文件输出日志内容。
演示环境
IntelliJ IDEA 2018.2.1 (Community Edition)
Maven 3.5.4
Spring Boot 2.1.1.RELEASE
了解Spring Boot
默认日志
SLF4J(Simple Logging Facade For Java)是一个针对于各类Java日志框架的统一抽象。Java日志框架有很多比如常用的有java.util.logging
, log4j
, logback
,commons-logging
,Spring
框架使用的是Jakarta Commons Logging API (JCL)
。而SLF4J
定义了统一的日志抽象接口,而真正的日志实现,则是看我们引入了哪些日志的实现。也有出现在SLF4J
的之前的日志框架,比如:java.util.logging
、 log4j
等。这些框架并没有实现SLF4J
的接口,当我们使用的框架的默认日志实现不同的话,很容易造成错乱。所以这个时候就出现了很多的过度包。比如:
java.util.logging
--jul-to-slf4j.jarlog4j
--log4j-to-slf4j.jarcommons-logging
--jcl-over-slf4j.jar
有了这些过度的包,我们就可以通过调用SLF4J
的API来调用任一日志实现,不会出现日志框架冲突等问题,我们的项目中只需要一个SLF4J
的实现即可。
Logback是log4j框架的作者开发的新一代日志框架,它效率更高、能够适应诸多的运行环境,同时天然支持SLF4J
。
1、Spring Boot
日志的依赖关系
我们的spring-boot-starter
依赖了spring-boot-starter-logging
,这个spring-boot-starter-logging
就是整合了SLF4J
和Logback
。所以我们可以说Spring Boot
默认使用的是Logback
作日志实现。并且日志的默认等级是INFO
,可以在这儿spring-boot-2.1.1.RELEASE.jar!/org/springframework/boot/logging/logback/base.xml
文件中看到。
2、Spring Boot
日志实现的优先级
我们的Spring Boot
的源码中,在这个类中定义了日志实现方式的获取org.springframework.boot.logging.LoggingSystem
,我们来读一下源码:
public abstract class LoggingSystem {
private static final Map<String, String> SYSTEMS;
static {
Map<String, String> systems = new LinkedHashMap<>();
systems.put("ch.qos.logback.core.Appender",
"org.springframework.boot.logging.logback.LogbackLoggingSystem");
systems.put("org.apache.logging.log4j.core.impl.Log4jContextFactory",
"org.springframework.boot.logging.log4j2.Log4J2LoggingSystem");
systems.put("java.util.logging.LogManager",
"org.springframework.boot.logging.java.JavaLoggingSystem");
SYSTEMS = Collections.unmodifiableMap(systems);
}
public static LoggingSystem get(ClassLoader classLoader) {
String loggingSystem = System.getProperty(SYSTEM_PROPERTY);
if (StringUtils.hasLength(loggingSystem)) {
if (NONE.equals(loggingSystem)) {
return new NoOpLoggingSystem();
}
return get(classLoader, loggingSystem);
}
return SYSTEMS.entrySet().stream()
.filter((entry) -> ClassUtils.isPresent(entry.getKey(), classLoader))
.map((entry) -> get(classLoader, entry.getValue())).findFirst()
.orElseThrow(() -> new IllegalStateException(
"No suitable logging system located"));
}
}
这里Spring Boot
默认添加了三种的日志实现logback
、log4j2
和jul
。然后这些被加载进了一个Map
中,在获取日志系统的方法中,使用findFirst()
来获取日志系统。所以我们这里可以大胆的说Spring Boot
日志级别是logback>log4j2>jul
。
这里只摘取了部分源码,作为分析使用。
配置Spring Boot
的日志
在这里Spring Boot
给我们提供了根据配置文件来修改默认配置。
1、根据propreties
文件配置
日志的默认级别是INFO
,如果想使用DEBUG
级别的日志,只需要在配置文件中添加:
debug=true控制日志等级,可以指定root
的日志等级,还可以指定具体包的日志等级:
logging.level.root=INFO
logging.level.xin.jerome=DEBUG
也可以对包进行分组后,在进行控制日志等级:
logging.group.tomcat=org.apache.catalina, org.apache.coyote, org.apache.tomcat
logging.level.tomcat=TRACE
将日志输出到具体的文件,默认文件大小10MB
,也可以指定绝对路径:
logging.file=xxx.log
logging.file=/var/log/xxx.log
将日志文件输出到具体的路径下,默认创建spring.log
文件(仅logback
支持):
logging.path=/var/log控制日志文件的大小(仅logback
支持):
logging.file.max-size=1MB控制日志文件存档的最大值(仅logback
支持):
logging.file.max-history=30格式化控制台输出(仅logback
支持):
logging.pattern.console=%d{yyyy‐MM‐dd} [%thread] %‐5level %logger{50} ‐ %msg%n格式化文件输出(仅logback
支持):
logging.pattern.file=%d{yyyy‐MM‐dd} [%thread] %‐5level %logger{50} ‐ %msg%n格式化日志日期输出(仅logback
支持):
logging.pattern.dateformat=yyyy-MM-dd HH:mm:ss.SSS2、根据xml
配置文件配置
由于日志服务一般都在ApplicationContext创建前就初始化了,它并不是必须通过Spring的配置文件控制。因此通过系统属性和传统的Spring Boot外部配置文件依然可以很好的支持日志控制和管理。
根据不同的日志系统,按如下规则组织配置文件名,就能被正确加载:
Logback:
logback-spring.xml
,logback-spring.groovy
,logback.xml
,logback.groovyLog4j2:
log4j2-spring.xml
,log4j2.xmlJDK (Java Util Logging):
logging.properties
上面是默认的命名规则,并且放在src/main/resources
下面即可。
当然使用配置的方式指定我们配置文件的位置:
logging.config=classpath:logback.xmlSpring Boot
官方推荐优先使用带有-spring
的文件名作为你的日志配置(如使用logback-spring.xml
,而不是logback.xml
),命名为logback-spring.xml
的日志配置文件,Spring Boot
可以为它添加一些Spring Boot
特有的配置项,由Spring Boot
解析日志配置,可以使用Profile功能,根据不同的环境配置不同的输出。看下面文件定义:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<property name="LOG_HOME" value="E:\\log" />
<property name="fileName" value="spring-boot-logback"></property>
<appender name="consoleLogAppender" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<springProfile name="dev">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</springProfile>
<springProfile name="!dev">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} - [%thread] - %-5level %logger{50} - %msg%n</pattern>
</springProfile>
</layout>
</appender>
<appender name="fileLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${fileName}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${fileName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<MaxHistory>365</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
</layout>
</appender>
<logger name="xin.jerome" level="debug" />
<logger name="org.springframework" level="debug" additivity="false"></logger>
<root level="info">
<appender-ref ref="consoleLogAppender" />
<appender-ref ref="fileLogAppender" />
</root>
</configuration>
解析一下这个配置文件,首先根节点<configuration>
:
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
定义属性变量<property/>
:
<!-- 定义日志的根目录 -->
<property name="LOG_HOME" value="E:\\log" />
<!-- 定义日志文件名称 -->
<property name="fileName" value="spring-boot-logback"></property>
格式化日志输出节点<appender>
,其中ch.qos.logback.core.ConsoleAppender
表示控制台的输出,ch.qos.logback.core.rolling.RollingFileAppender
表示已滚动的方式输出到日志文件。
<file>
标签作用是指定日志文件的所在位置。<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
决定RollingFileAppender
的行为,涉及文件移动和重命名。<fileNamePattern>
滚动时产生的文件的存放位置及文件名称。<MaxHistory>
控制保留的归档文件的最大数量。<maxFileSize>
控制日志文件的大小,当超过这个大小后开始滚动。<layout>#<pattern>
日志输出格式:
%d表示日期时间。
%thread表示线程名。
%-5level:级别从左显示5个字符宽度。
%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息。
%n是换行符。
日志对象结点<logger>
,主要用于存放日志对象,也可以定义日志类型、级别:
name:表示匹配的logger类型前缀,也就是包的前半部分。
level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR。
additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,
false:表示只用当前logger的appender-ref。
true:表示当前logger的appender-ref和rootLogger的appender-ref都有效
<root>
结点,root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。
在控制台日志输出的时候使用了<springProfile>
结点,可以与Spring Boot
配置的Profile
来结合使用,来控制不同环境的日志输出。
总结
经过我们上面的分析和演示,实现了Spring Boot
默认的日志框架logback
的配置使用。探究了Spring Boot
默认实现日志系统的优先级;以及通过简单的配置文件对Spring Boot
的日志系统进行了简单的改造,以及通过官方推荐的logback-spring.xml
文件,自定义我们的日志系统。
具体的代码可以参考GitHub:spring-boot-demo-logback小节。





