1 名词术语
相关背景知识我们还是需要了解的,有助于对正文内容的理解。
名词术语 | 释义 |
---|---|
Apache Common Logging | Apache下开源项目,commons-logging的目的是为“所有的Java日志实现”提供一个统一的接口,使项目与日志实现工具解耦;commons-logging和log4j都是Apache下的开源项目。commons-logging的目的是为“所有的Java日志实现”提供一个统一的接口,使项目与日志实现工具解耦,它自身的日志功能比较弱(只有一个简单的 SimpleLog),所以一般不会单独使用它。 |
Log4j / Log4j 2 | Apache下的开源项目,Log4j的功能非常强大,是目前最主流的java日志工具。Log4j 2.0 引入了新的插件系统、对 properties 的支持、对基于 JSON 配置的支持和配置的自动化重载。相比之前Log4j 的1.x 版本有了很大的性能提升。它支持很多已有的日志框架,包括 SLF4J、Commons Logging、Apache Flum、Log4j 1.x,并提供了新的程序员 API。 |
Java Util Logging | Java 的原生日志记录基础组件 |
Logback | 是一个日志框架,旨在取代Log4j,Log4j的改良版本,比Log4j拥有更多的特性,同时也带来很大性能提升。不过性能上没有Log4j 2好。 |
SLF4J | 跟Apache Common Logging一样,也是一套接口,现在流行的日志框架和接口组合就是Commons Logging加Log4j 、SLF4J加Logback、slf4j log4j2 |
Mockito | Mockito是一个通用的模拟框架,可用于单元测试,尤其是考虑到依赖注入而设计的类。Mockito也可以用来测试Spring Controller,但不是针对性的支持。 |
MockMVC | MockMVC是Spring框架的配套产品,有助于测试Spring Controllers。MockMVC更加具体,与Mockito相比,通用性可能要差得多,不过对于测试Spring MVC 中Restful API是比较好的。 |
2 日志记录
Spring Boot
使用Apache Commons Logging
接口记录所有内部日志记录。Spring Boot
的默认配置对Java Util Logging
,Log4j2
和Logback
日志记录器的使用都提供了支持。如果你使用的是Spring Boot Starters
,默认使用的Logback
就为日志记录提供很好的支持。下面我们分几部分对如何做日志记录以及配置不同的日志记录器做说明,在Spring Boot
中只需要通过一些简单的配置即可支持各种日志记录。
2.1 默认零配置记录日志
默认启动日志记录是由spring-boot-starter-logging
依赖项决定的,并且它是自动配置的,该自动配置可根据提供的配置启用任何受支持的日志记录器(Java Util Logging,Log4J2和Logback),虽然我们不提供任何日志相关的配置,但是我们仍然能够在控制台上看到日志打印,这是因为Spring boot
使用了Logback
提供了默认的日志记录支持。但是我们上一篇文章里为啥没有看到pom.xml
文件里有导入spring-boot-starter-logging
这个依赖项呢?
Spring Boot
的内部日志记录是使用Apache Commons Logging
接口编写的,因此它是唯一的强制性依赖项。在Spring boot1.x
的时候我们还需要手动导入,但是到了Spring boot2.x
,它是间接导入的,即我们依赖了spring-boot-starter-web
这个依赖项时,它就依赖了spring-boot-starter-logging
,这个时候就导入了日志记录功能。从STS
的pom.xml文件依赖展开就可以看到:
因此,Spring boot
自动配置提供使用Logback
的默认日志记录,并且这些配置文件中提供了默认日志记录的参数配置。从Spring Boot
的日志记录源码就可以看到( https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml ) 。
2.1.1 使用日志记录器打印日志
在应用程序代码中添加日志记录语句,我们使用SLF4J
接口中的org.slf4j.Logger
和org.slf4j.LoggerFactory
。它提供了许多有用的日志记录方法,也使日志记录实现与应用程序相分离。
代码语言:javascript复制注意:日志接口是很多,这里我们选择了SLF4J API。还有apache.logging/java.util.logging等
// 使用Log4j2则使用apache logging接口
// import org.apache.logging.log4j.LogManager;
// import org.apache.logging.log4j.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application
{
private static final Logger LOGGER=LoggerFactory.getLogger(Test02HelloworldApplication.class);
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
LOGGER.info("简单的日志记录测试 : {} {} = {}", 1, 2, 3);
}
}
控制台打印如下:
代码语言:javascript复制2019-10-29 21:37:39.818 INFO 16244 --- [ main] c.xiaobaiai.Test02HelloworldApplication : 简单的日志记录测试 : 1 2 = 3
2.1.2 日志记录器的日记级别
Logback
支持设置ERROR
,WARN
,INFO
,DEBUG
、TRACE
或OFF
作为日志记录级别,按日志抑制优先级从高到低。默认情况下,日志记录级别设置为INFO
。这意味着DEBUG
和TRACE
消息不可见。
要启用DEBUG
或TRACE
日志记录级别,我们可以在application.properties
文件中设置日志记录级别。另外,我们也可以在启动应用程序时在命令行上传递--debug
或--trace
参数。
# In application.properties file
# 方法一: 该属性置为true的时候,核心Logger(包含嵌入式容器、hibernate、spring)会输出更多内容,但是你自己应用的日志并不会输出DEBUG级别的日志
debug=true
# 方法二:将日志记录级别应用于特定的软件包。
logging.level.com.xiaobaiai=DEBUG
logging.level.org.springframework=ERROR
logging.level.root=DEBUG
# In Console
$ java -jar target/xx-app-0.0.1-SNAPSHOT.jar --trace
注意:如果使用不同的日志级别多次定义了软件包的日志级别,则将使用最低级别。TRACE最低,ERROR最高。
2.1.3 日志记录器的日志记录格式
默认的日志记录格式在Spring Boot
日志记录器Logback
源码文件default.xml
中可以看到:
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
日志最后输出如下信息:
- 日期和时间:毫秒精度,便于排序
- 日志级别:ERROR, WARN, INFO, DEBUG, or TRACE
- 进程ID
---
分隔符用于区分实际日志消息的开始- 线程名称:用方括号括起来(对于控制台输出可能会被截断)
- 名称:这通常是类的名称(通常缩写)
- 最后就是日志信息体
要定义日志最后的输出格式,使用logging.pattern.console
和logging.pattern.file
属性。
# Logging pattern for the console
# 不支持JDK Logger
logging.pattern.console= %d{yyyy-MM-dd HH:mm:ss} - %logger{36} - %msg%n
# Logging pattern for file
# 不支持JDK Logger
logging.pattern.file= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%
2.1.4 将日志输出到文件
默认情况下,Spring boot
日志仅记录到控制台。如果要启用文件日志记录,则可以使用简单的属性logging.file
或logging.path
轻松实现。
# 输出到指定路径,默认文件名为spring.log
logging.file.path=C:\Work\sts4\test_02_helloworld\logs
# 文件名设置,使用了该项配置,则会覆盖path设置,直接在工程当前目录下生成日志
logging.file.name=logfilename.log
# 路径与文件名结合(该配置项已被遗弃)
logging.file=${logging.file.path}/log.log
# 输出到文件最大内容限制大小,达到最大后,会截断
# 默认是10M,而且该设置项只对默认的Logback有效,单位GB/MB/KB等
logging.file.max-size = 10MB
2.1.5 日志彩色输出
如果你的终端支持ANSI,设置彩色输出会让日志更具可读性。通过在application.properties
中设置spring.output.ansi.enabled
参数来支持。
# NEVER:禁用ANSI-colored输出(默认项)
# DETECT:会检查终端是否支持ANSI,是的话就采用彩色输出(推荐项)
# ALWAYS:总是使用ANSI-colored格式输出,若终端不支持的时候,会有很多干扰信息,不推荐使用
spring.output.ansi.enabled=DETECT
2.1.6 自定义日志配置
根据不同的日志系统,你可以按如下规则组织配置文件名,就能被正确加载:
Logback
:logback-spring.xml
,logback-spring.groovy
,logback.xml
,logback.groovy
,logback-spring-xxx.xml
Log4j
:log4j-spring.properties
,log4j-spring.xml
,log4j.properties
,log4j.xml
Log4j2
:log4j2-spring.xml
,log4j2.xml
JDK (Java Util Logging)
:logging.properties
Spring Boot官方推荐优先使用带有-spring
的文件名作为你的日志配置(如使用logback-spring.xml
,而不是logback.xml
),命名为logback-spring.xml
的日志配置文件,Spring boot可以为它添加一些Spring boot
特有的配置项。
上面是默认的命名规则,并且放在src/main/resources
下面即可。
如果你即想完全掌控日志配置,但又不想用logback.xml
作为Logback配置的名字,可以在application.properties
配置文件里面通过logging.config
属性指定自定义的名字:
logging.config=classpath:logging-config.xml
这里简单讲述Logback
的一个自定义配置,具体的可以参见官方文档http://logback.qos.ch/manual/configuration.html
配置文件主要实现的功能有:
- 对控制台和日志保存到文件进行了配置
- 对控制台的日志级别进行了控制
- 对输出到文件进行了分割处理设置,包括单日志文件大小,所有日志文件大小限制,以及日志保存的天数
- 对输出到文件的日志命名方式进行了设置
- 对指定包的日志输出级别进行了控制
<?xml version="1.0" encoding="UTF-8"?>
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
当scan为true时,此属性生效。默认的时间间隔为1分钟。debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。-->
<configuration scan="true" scanPeriod="60 seconds"
debug="false">
<!-- 每个logger都关联到logger上下文,默认上下文名称为“default”。但可以使用contextName标签设置成其他名字,用于区分不同应用程序的记录,如打印日志如下中xiaobaiai
10:39:28.964 xiaobaiai [main] DEBUG c.x.Test02HelloworldApplication - 简单的日志记录测试
: 1 2 = 3 -->
<contextName>xiaobaiai</contextName>
<!-- property用来定义变量值的标签,property标签有两个属性,name和value;其中name的值是变量的名称,value的值时变量定义的值
这里定义了log.path这个变量,下面会有引用这个变量 -->
<property name="log.path"
value="/Users/Ethanm/Documents/spring-log" />
<!--输出到控制台 -->
<appender name="console"
class="ch.qos.logback.core.ConsoleAppender">
<!-- 定义过滤器,ERROR级别 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName %magenta([%thread]) %highlight(%-5level) %logger{36}.%M - %msg%n</pattern>
</encoder>
</appender>
<!--输出到文件 -->
<appender name="file"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 最新的log文件 -->
<file>${log.path}/log_newest.log</file>
<encoder>
<!-- %d-以SimpleDateFormat允许的格式输出日志消息发生的时间 %thread-输出发生日志消息的线程的名称。$-5level-输出日志消息的日志记录级别。
%logger{36}-输出发生日志消息的包 类名。括号内的数字表示包 类名的最大长度。%M-输出发生日志消息的方法的名称(性能较差,不建议生成环境使用)
%msg-输出实际的日志消息 %magenta()-将括号中包含的输出的颜色设置为洋红色(其他颜色可用)。%highlight()-将括号中包含的输出颜色设置为取决于日志记录级别(例如ERROR
= red) -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger{36}.%M - %msg%n</pattern>
</encoder>
<!-- 日志文件分割设置 -->
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>
${log.path}/log_%d{yyyy-MM-dd}_%i.log
</fileNamePattern>
<maxFileSize>3KB</maxFileSize>
<!-- 只保存最近10天日志 -->
<maxHistory>10</maxHistory>
<!-- 定义日志文件上限,如果所有日志超过这个大小,则会删除旧的日志 -->
<totalSizeCap>100MB</totalSizeCap>
</rollingPolicy>
</appender>
<!-- root是根logger,不能有name和additivity属性,是有一个level -->
<!-- appender是一个日志打印的组件,这里组件里面定义了打印过滤的条件、打印输出方式、滚动策略、编码方式、打印格式等 如果我们不使用一个logger或者root的appender-ref指定某个具体的appender时,它就不会生效 -->
<root level="info">
<appender-ref ref="console" />
<appender-ref ref="file" />
</root>
<!-- logger标记用来设置某一个包或者具体的某一个类的日志打印级别以及指定appender -->
<logger name="com.xiaobaiai" level="WARN" additivity="false">
<appender-ref ref="console" />
</logger>
</configuration>
2.2 Log4j2 记录日志
2.2.1 引入Log4j2
默认日志记录使用了Logback
,首先我们需要在pom.xml
中去掉Logback
,引入Log4j2
。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- 用exclusion排除掉默认日志记录器Logback -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
2.2.2 添加log4j2配置文件
与Logback
类似,在资源文件夹下(resources)添加如下形式的配置文件,都可以被扫描到:
- log4j2-spring.xml
- log4j2.xml
配置文件设置与Logback
大同小异:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
<Properties>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} %p %m%n</Property>
<Property name="APP_LOG_ROOT">c:/temp</Property>
</Properties>
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="${LOG_PATTERN}" />
</Console>
<RollingFile name="file"
fileName="${APP_LOG_ROOT}/SpringBoot2App/application.log"
filePattern="${APP_LOG_ROOT}/SpringBoot2App/application-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="${LOG_PATTERN}" />
<Policies>
<SizeBasedTriggeringPolicy size="19500KB" />
</Policies>
<DefaultRolloverStrategy max="1" />
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="console" />
<AppenderRef ref="file" />
</Root>
</Loggers>
</Configuration>
2.3 内嵌WEB服务器日志设置
这里就不展开了,到了实际使用的时候,再来详细了解。
代码语言:javascript复制#tomcat
server.tomcat.basedir=C:/temp/logs
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
logging.level.org.apache.tomcat=DEBUG
logging.level.org.apache.catalina=DEBUG
#undertow
server.undertow.accesslog.directory=C:/temp/logs
server.undertow.accesslog.enabled=true
server.undertow.accesslog.pattern=%t %a "%r" %s (%D ms)
logging.level.io.undertow.server=DEBUG
logging.level.io.undertow.websockets=DEBUG
#jetty
server.jetty.accesslog.filename=/var/log/jetty-access.log
server.jetty.accesslog.enabled=true
logging.level.org.eclipse.jetty=INFO
logging.level.org.eclipse.jetty.websocket=DEBUG
3 总结
本篇文章让我们对主流的日志接口Apache common logging
和SLF4J
有了个了解,Logback
是Spring boot
中默认配置的日志记录器,我们对如何在application.properties
中配置日志相关配置做了详细说明,并对如何自定义Logback
配置也作出了详细说明,最后介绍了如何切换日志记录器到Log4j2
以及如何配置Log4j2
给出了示例。扩展部分对内嵌WEB服务器的日志配置也给出了个简单的示例。总之,我们对Spring boot
的日志这一块应该不会再陌生了。
4 参考文档
- http://commons.apache.org/proper/commons-logging/
- https://www.infoq.com/news/2014/07/apache-log4j2/
- https://stackify.com/compare-java-logging-frameworks/
- https://blog.souche.com/logback-log4j-log4j2shi-ce/
- https://howtodoinjava.com/spring-boot2/logging/spring-boot-logging-configurations/
- https://www.codingame.com/playgrounds/4497/configuring-logback-with-spring-boot
- https://howtodoinjava.com/spring-boot2/logging/embedded-server-logging-config/