市面上常见的日志框架有很多。通常情况下,日志是由一个抽象层+实现层的组合来搭建的,而用户通常来说不应该直接使用具体的日志实现类,应该使用日志的抽象层。
抽象层:JCL(Jakarta Commons Logging)、SLF4j(Simple Logging Facade for Java)、jboss-logging
实现层:Log4j 、JUL(java.util.logging)、Log4j2、Logback
SpringBoot 默认选择的是 SLF4J + Logback 的组合,如果不需要更改为其他日志系统(如 Log4j2 等),则无需多余的配置,LogBack 默认会将日志打印到控制台上。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
dependency>
由于新建的 Spring Boot 项目一般都会引用 spring-boot-starter 或者 spring-boot-starter-web,而这两个起步依赖中都已经包含了对于 spring-boot-starter-logging 的依赖,所以,我们无需额外添加依赖。
@RestController
@RequestMapping("/user")
public class UserController {
static final Logger LOG = LoggerFactory.getLogger(UserController.class);
@RequestMapping("/listUser")
public String listUser() {
LOG.trace("sl4j for trace");
LOG.debug("slf4j for debug");
LOG.info("slf4j for info");
LOG.warn("slf4j for warn");
LOG.error("slf4j for error");
return "listUser";
}
}
日志级别从小到大为 trace < debug < info < warn < error < fatal
,Spring Boot默认日志级别设置为 INFO
级别输出到控制台,只能展示大于或等于设置的日志级别的日志;也就是说springboot默认级别为INFO
,那么在控制台展示的日志级别只有INFO 、WARN、ERROR、FATAL
1、可以在 applicaition.yml
配置 文件中修改日志级别。比如下面将全局日志级别都改成 trace,因此系统所有的日志都能看到:
logging:
# 设置日志级别
level:
root: trace
2、也可以只设置某个包的日志级别,这样能够更方便准确地定位问题。比如下面配置,只对所有 cn.zysheep.mapper包下面产生的日志级别改成 debug:如: Mybatis的SQL语句需要在debug日志级别才能打印,在开发环境时可以设置SQL打印,生产环境可以关闭日志打印。设置成高级别的日志
logging:
# 设置日志级别
level:
root: trace
cn.zysheep.mapper: debug
1、项目上线后通常还需要将日志输出到文件。我们只需要通过 logging.file.path 配置文件存放路径
2、通过 logging.file.path 生成的日志文件名字为 spring.log,如果需要自定义文件名字,则通过 logging.file.name 属性进行配置(此时不需要再配置 logging.file.path)
3、无论何种设置,Spring Boot 都会自动按天分割日志文件,也就是说每天都会自动生成一个新的 log 文件,而之前的会自动打成 GZ 压缩包
4、还可以设置日志文件的保留时间logging.file.max-size
默认10MB,以及单个文件的大小logging.file.max-history
默认7天
logging.file.name | logging.file.path | 示例 | 说明 |
---|---|---|---|
(none) | (none) | 只在控制台输出 | |
指定文件名 | (none) | demo.log | 输出到当前项目根路径下的 demo.log 文件中 |
(none) | 指定目录 | /logs | 输出到当前项目所在磁盘根路径下的/logs目录中的 spring.log 文件中 |
指定文件名 | 指定目录 | /logs/demo.log | 当两个同时指定时,采用的是logging.file.name 指定。推荐使用logging.file.name 设置即可,因为它可指定目录和文件名 |
logging:
# 设置日志级别
level:
cn.zysheep.mapper: debug
# 生成日志文件
file:
# 配置文件存放路径
# path: /logs
# 自定义文件名字
name: /logs/demo.log
# 日志文件大小
max-size: 10MB
# 保留的日志时间
max-history: 7
1、可以分别修改在控制台输出的日志格式,以及文件中日志输出的格式:
%d{HH:mm:ss.SSS}:日志输出时间
%-5level:日志级别,并且使用 5 个字符靠左对齐
%thread:输出日志的进程名字,这在 Web 应用以及异步任务处理中很有用
%logger:日志输出者的名字
%msg:日志消息
%n:平台的换行符
logging:
pattern:
# 修改在控制台输出的日志格式
console: '%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger : %msg%n'
# 修改输出到文件的日志格式
file: '%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger : %msg%n'
YML中双引号和单引号的区别:
" "(双引号): 不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思
- name: “zhangsan \n lisi”:输出:zhangsan \n lisi
’ '(单引号): 会转义特殊字符,特殊字符最终只是一个普通的字符串数据
- name: ‘zhangsan \n lisi’;输出:zhangsan 换行 lisi
2、上面效果图可以发现,原先 Spring Boot 默认使用 Logback 来进行日志输出时,控制台不同参数会输出为不同的颜色。而一旦我们修改了日志格式,彩色也随之消失。如果想让不同类型的数据具有不同的高亮效果,可以改用如下配置:
logging:
pattern:
# 修改在控制台输出的日志格式
console: '%d{yyyy-MM-dd HH:mm:ss} %clr(%5p) [%thread] %clr(%logger){cyan} : %msg%n'
# 修改输出到文件的日志格式
file: '%d{yyyy-MM-dd HH:mm:ss} %clr(%5p) [%thread] %clr(%logger){cyan} : %msg%n'
依赖实现分析
1、springboot-logging项目为springboot项目,其中引入了spring-boot-starter-web模块
2、spring-boot-starter-web 中引入了 spring-boot-starter 启动器
3、spring-boot-starter 中引入了 spring-boot-starter-logging 日志启动器
4、spring-boot-starter-logging 日志启动器 采用的是 logback 日志框架
总结: SpringBoot中默认日志启动器为 spring-boot-starter-logging ,默认采用的是 logback 日志框架
5、在spring-boot-2.3.1.RELEASE.jar! \org\springframework\boot\logging\logback\base.xml做了日志的默认配置
<included>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE"value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
root>
included>
SpringBoot对具体的日志实现类都有默认的实现。如果spring boot的日志功能无法满足我们的需求,我们可以自已定义的日志配置文件。
在类路径下,存放对应日志框架的自定义配置文件即可;SpringBoot就不会使用它默认的日志配置文件了
Logging System | Customization |
---|---|
Logback | logback-spring.xml , logback-spring.groovy , logback.xml , logback.groovy |
Log4j | log4j-spring.properties , log4j-spring.xml , log4j.properties, log4j.xml |
Log4j2 | log4j2-spring.xml , log4j2.xml |
JDK (Java Util Logging) | logging.properties |
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logbackcontextName>
<property name="log.path" value="logs/log" />
<property name="CONSOLE_LOG_PATTERN"
value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) | %highlight(%-5level) | %blue(%thread) | %blue(%file:%line) | %green(%logger) | %cyan(%msg%n)"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}Pattern>
<charset>UTF-8charset>
encoder>
appender>
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/log_info.logfile>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
<charset>UTF-8charset>
encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.logfileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>15maxHistory>
rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFOlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/log_warn.logfile>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
<charset>UTF-8charset>
encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.logfileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>15maxHistory>
rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warnlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/log_error.logfile>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
<charset>UTF-8charset>
encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.logfileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>15maxHistory>
rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERRORlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<logger name="org.springframework" level="debug" additivity="false"/>
<logger name="cn.zysheep.mapper" level="debug" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
root>
configuration>
logback.xml :是直接就被日志框架加载了。
logback-spring.xml:配置项不会被日志框架直接加载,而是由 SpringBoot 解析日志配置文件
logback.xml加载早于application.properties,所以如果你在logback.xml使用了变量时,而恰好这个变量是写在application.properties时,那么就会获取不到,只要改成logback-spring.xml就可以解决。
因为logback-spring.xml是由 SpringBoot 解析日志配置文件,故可以使用SpringBoot 的 Profile 特殊配置
logback-spring.xml
使用 Profile 特殊配置多环境在不同开发环境输出不同的日志
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logbackcontextName>
<property name="log.path" value="logs/log.log" />
<property name="CONSOLE_LOG_PATTERN"
value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}Pattern>
<charset>UTF-8charset>
encoder>
appender>
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/log_info.logfile>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
<charset>UTF-8charset>
encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.logfileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>15maxHistory>
rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFOlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/log_warn.logfile>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
<charset>UTF-8charset>
encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.logfileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>15maxHistory>
rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warnlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/log_error.logfile>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
<charset>UTF-8charset>
encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.logfileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>15maxHistory>
rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERRORlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<springProfile name="dev">
<logger name="com.guli" level="DEBUG" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
root>
springProfile>
<springProfile name="pro">
<logger name="com.guli" level="WARN" />
<root level="INFO">
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="WARN_FILE" />
root>
springProfile>
configuration>
指定运行环境: --spring.profiles.active=dev
注意: 若使用 logback.xml 作为日志配置文件,还指定 Profile 特殊配置,则会有以下错误,便也证明前面所说logback.xml是直接就被日志框架加载。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
dependency>
# 根日志,配置了日志级别为 INFO,预定义了名称为 console、file 两种附加器
log4j.rootLogger=INFO, console, file
# 指定包目录输出不同级别的日志
log4j.logger.cn.zysheep.mapper=debug, console, file
log4j.additivity.cn.zysheep.mapper=false
# console 附加器,日志输出位置在控制台
log4j.appender.console=org.apache.log4j.ConsoleAppender
# console 附加器,采用匹配器布局模式
log4j.appender.console.layout=org.apache.log4j.PatternLayout
# console 附加器,日志输出格式为:日期 日志级别 [类名] - 消息换行符
log4j.appender.console.layout.ConversionPattern=%d %p [%c] - %m%n
# file 附加器,每天产生一个日志文件
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
# file 附加器,日志文件输出位置 logs/log.log
log4j.appender.file.File=logs/log.log
# file 附加器,采用匹配器布局模式
log4j.appender.file.layout=org.apache.log4j.PatternLayout
# 日志文件最大值
log4j.appender.A3.MaxFileSize=1024KB
# 最多纪录文件数
log4j.appender.A3.MaxBackupIndex=10
# file 附加器,日志输出格式为:日期 日志级别 [类名] - 消息换行符
log4j.appender.file.layout.ConversionPattern=%d %p [%c] - %m%n
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-log4j2artifactId>
dependency>
<configuration monitorInterval="5">
<Properties>
<property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
<property name="FILE_PATH" value="./logs/log4j2" />
<property name="FILE_NAME" value="log4j2-demo" />
Properties>
<appenders>
<console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${LOG_PATTERN}"/>
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
console>
<File name="Filelog" fileName="${FILE_PATH}/test.log" append="false">
<PatternLayout pattern="${LOG_PATTERN}"/>
File>
<RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
Policies>
<DefaultRolloverStrategy max="15"/>
RollingFile>
<RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log" filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
Policies>
<DefaultRolloverStrategy max="15"/>
RollingFile>
<RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
Policies>
<DefaultRolloverStrategy max="15"/>
RollingFile>
appenders>
<loggers>
<logger name="org.mybatis" level="info" additivity="false">
<AppenderRef ref="Console"/>
logger>
<Logger name="org.springframework" level="info" additivity="false">
<AppenderRef ref="Console"/>
Logger>
<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="Filelog"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
root>
loggers>
configuration>
SpringBoot中默认使用Logback进行日志输出,可以同时使用通过logback的配置文件logback.xml
或是SpringBoot框架的配置文件application.yml
进行配置。
logback.xml
<configuration>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
root>
configuration>
application.yml
logging:
level:
root: debug
测试类
@RestController
@RequestMapping("/user")
public class UserController {
static final Logger LOG = LoggerFactory.getLogger(UserController.class);
@RequestMapping("/listUser")
public String listUser() {
LOG.trace("sl4j for trace");
LOG.debug("slf4j for debug");
LOG.info("slf4j for info");
LOG.warn("slf4j for warn");
LOG.error("slf4j for error");
return "listUser";
}
}
总结:
application.yml
中日志配置的优先级比logback.xml
高