在开发中除了使用到的类会打印出日志,开发者自己也需要打印日志来记录开发流程、运行位置以及异常信息等等。
项目中的日志能够很好的帮助我们找到bug的出现位置,以及出现bug的原因。由此可见,利用好日志能够大大替身开发者的开发效率。
目前市面比较流行的日志框架:slf4j、log4j、log4j2、logback。
slf4j:是对所有日志框架制定的一种规范、标准、接口,并不是一个框架的具体的实现,因为接口并不能独立使用,需要和具体的日志框架实现配合使用
(如log4j、logback),使用接口的好处是当项目需要更换日志框架的时候,只需要更换jar和配置,不需要更改相关java代码
log4j、log4j2:log4j2是log4j的升级版。目前log4j以及停止更新了,所以一般用的都是log4j2。而且在多线程情况下,异步日志器具有比Log4j 1.x和Logback
高出10倍的吞吐性能以及更低的延迟。log4j2还支持scala语言。
logback:与Log4j同出一源,都出自Ceki Gülcü之手;但是logback拥有更好的特性,是用来取代log4j的一个日志实现方案。Logback是slf4j的原生实现,与
Log4j不同(Log4j可以脱离Slf4j单独使用),logback并不建议单独使用,它需要与sfl4j结合起来使用。
目前市面上用的最多的结合以及亲测推荐的日志组合就是:slf4j + logback
日志级别
日志级别有8个(从高到低): OFF(关闭),FATAL(致命),ERROR(错误),WARN(警告),INFO(信息),DEBUG(调试),TRACE(跟踪),ALL
(所有),默认的日志配置在消息写入时将消息回显到控制台。默认情况下,将记录错误级别、警告级别和信息级别的消息。
Trace:是追踪,就是程序推进以下,你就可以写个trace输出,所以trace应该会特别多,不过没关系,我们可以设置最低日志级别不让他输出.
Debug:指出细粒度信息事件对调试应用程序是非常有帮助的.
Info:消息在粗粒度级别上突出强调应用程序的运行过程.
Warn:输出警告及warn以下级别的日志.
Error:输出错误信息日志.
此外OFF表示关闭全部日志,ALL表示开启全部日志。
Log4j定义了上述8个级别的log,而SLF4J和Logback没有定义FATAL级别。Logback没有FATAL致命级别。它被映射到ERROR错误级别
一般用的最多的是ERROR > WARN > INFO > DEBUG
Spring Boot项目
SpringBoot采用的默认的日志框架就是slf4j+logback,所以配置的时候无需在pom.xml中添加依赖,我们只需要手动添加配置文件就好。
普通maven项目
导入依赖
<dependencies>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.32version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.7version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.2.7version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-accessartifactId>
<version>1.2.7version>
dependency>
dependencies>
logback.xml 和 logback-spring.xml 的区别
logback.xml 和 logback-spring.xml 都可以用来配置logback,但是2者的加载顺序是不一样的(logback.xml 由日志框架加载,而 logback-spring.xml 由
SpringBoot来加载)。
logback.xml 加载早于 application.properties,所以如果你在logback.xml使用了变量时,而恰好这个变量是写在application.yaml时,那么就会获取不到。
logback-spring.xml这样的命名方式是官方推荐的,使用 logback.xml 的命名直接被日志框架识别了,而使用logback-spring.xml这样的命名日志框架就不直接加
载,而由SpringBoot来加载,这样在日志配置文件中可以使用
标签,可以指定某配置项只在某个环境下生效(即开发环境dev或是生产环境
pro等)推荐使用logback-spring.xml
logback.xml 配置文件的加载机制
logback在启动时,日志框架会根据以下步骤寻找 logback.xml 配置文件(而 logback-spring.xml 是由springboot加载的):
在classpath中寻找logback-test.xml文件;
如果找不到logback-test.xml,则在 classpath中寻找logback.groovy文件;
如果找不到 logback.groovy,则在classpath中寻找logback.xml文件;
如果上述的文件都找不到,则logback会使用JDK的SPI机制查找 META-INF/services/ch.qos.logback.classic.spi.Configurator中的 logback 配置实现类,这个
实现类必须实现Configuration接口,使用它的实现来进行配置。
如果上述操作都不成功,logback 就会使用它自带的 BasicConfigurator 来配置,并将日志输出到console。
loggback配置说明
位置(resource目录下) | 说明 | |
---|---|---|
官方推荐 | logback-spring.xml | 默认读取resources目录下的 logback-spring.xml |
自定义位置 | log/logback-spring.xml | application.yml或者properties中配置: logging.config=classpath:log/logback-spring.xml |
logback.xml | logback.xml | 默认读取resources目录下的 logback.xml |
logback.xml位置 | log/logback.xml | application.yml或者properties中配置: logging.config=classpath:log/logback.xml, |
使用官方的推荐配置,在resources目录下新建logback-spring.xml,填写内容如下(只输出日志到控制台)。使用官方推荐配置时,application.yml或者properties中可以不加配置。
<configuration>
<property name="log.path" value="/home/logs" />
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}pattern>
encoder>
appender>
<root level="info">
<appender-ref ref="console" />
root>
configuration>
Spring Boot配置说明
logback文件名为logback-spring.xml,logback.xml,且位于resources目录下时,可以不添加任何配置。否则至少需要在配置application.properties文件中添加
属性 logging.config=classpath:log/logback-spring.xml 指定日志配置文件的位置。
# 日志配置
logging:
# 指定配置文件的路径
config: classpath:log/logback-spring.xml
level:
# root表示整个项目,默认级别为info
root: info
# com.demo包的日志级别为debug
com.founder: debug
# org.springframework包的日志级别为warn
org.springframework: warn
Logback使用主要依赖于Logger、Appender 和 Layout 这三个类之上
主要标签的用处:
configuration节点有三个属性:
<configuration scan="true" scanPeriod="60 seconds" debug="false">
configuration>
用来设置上下文名称,每个logger都关联到logger上下文,默认上下文名称为default。但可以使用设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改。
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>myAppNamecontextName>
configuration>
用来定义变量值,它有两个属性name和value,通过定义的值会被插入到logger上下文中,可以使“${}”来使用变量。name: 变量的名称,value: 变量定义的值。
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="name" value="cvzhanshi" />
<contextName>${name}contextName>
configuration>
获取时间戳字符串,有两个属性key和datePattern,其他节点可以通过${key}来获取到这个时间。
的名字;<configuration scan="true" scanPeriod="60 seconds" debug="false">
<timestamp key="nowDate" datePattern="yyyyMMdd'T'HHmmss"/>
<contextName>${nowDate}contextName>
configuration>
负责写日志的组件,它有两个必要属性name和class。name指定appender名称,class指定appender的全限定名。
ConsoleAppender,把日志输出到控制台
有以下子节点
:对日志进行格式化。(具体参数稍后讲解 )
:字符串System.out(默认)或者System.err。示例配置表示把>=DEBUG级别的日志都输出到控制台:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
encoder>
appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
root>
configuration>
FileAppender,把日志添加到文件
有以下子节点
:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。
:如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。
:对记录事件进行格式化。
:如果是 true,日志会被安全的写入文件,即使其他的FileAppender也在向此文件做写入操作,效率低,默认是 false。示例配置表示把>=DEBUG级别的日志都输出到testFile.log
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>testFile.logfile>
<append>trueappend>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
encoder>
appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
root>
configuration>
RollingFileAppender,滚动记录文件
滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。有以下子节点:
:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。
:如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。
:当发生滚动时,决定RollingFileAppender的行为,涉及文件移动和重命名。属性class定义具体的滚动策略类。rollingPolicy属性class定义具体的滚动策略类,有3类:
配置表示每天生成一个日志文件,保存30天的日志文件
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logFile.%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>30maxHistory>
rollingPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%npattern>
encoder>
appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
root>
configuration>
用来设置某一个包或具体的某一个类的日志打印级别、以及指定appender。logger仅有一个name属性,一个可选的level和一个可选的additivity属性。可以包含零个或多个appender-ref元素,标识这个appender将会添加到这个logger。
<logger name="com.deepoove.poi" level="warn" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="fileLog" />
logger>
它也是logger元素,是根logger,所有logger的上级。只有一个level属性,因为name已经被命名为"root",且已经是最上级了。
通过springProperty标签来引用spring boot的配置文件信息
<springProperty scope="context" name="log.path" source="path.log"/>
示例
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logbackcontextName>
<property name="log.path" value="D:/nmyslog/nmys" />
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>infolevel>
filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}Pattern>
<charset>UTF-8charset>
encoder>
appender>
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/log_debug.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}/debug/log-debug-%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>debuglevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
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.nmys.view" level="debug"/>
springProfile>
<root level="info">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
root>
configuration>
必需appender 配置为rolling的才能滚动
在FixedWindowRollingPolicy里面不能配置%d{yyyy-MM-dd}, 如果配置了的话,会导致滚动失败,不仅不能生成滚动文件,当前文件也不再写入,只能且必需配置%i。FixedWindowRollingPolicy可以和SizeBasedTriggeringPolicy配合使用。
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<FileNamePattern>tests.%i.log.zipFileNamePattern>
<MinIndex>1MinIndex>
<MaxIndex>3MaxIndex>
rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>5MBMaxFileSize>
triggeringPolicy>
TimeBasedRollingPolicy 不能和SizeBasedTriggeringPolicy配合使用,如果两个同时配置,在达到最大文件大小的时候,会导致即不会生成滚动文件,当前文件也不再写入。
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logFile.%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>30maxHistory>
rollingPolicy>
springProfile 配置为dev时, 输出端可以为console, 但配成prod时, 切记关闭console输出。
SpringBoot默认读取resources下的,若是放到了自定义的路径下, 则需要在application.yml中配置其具体路径。
有时候需要打印低级别(如debug)的日志,不要把
改成
,这样日志会出现很多其他框架的输出的信息,不利于排查日志,可以单独给某个包指定日志输出级别,这样只有被设置为debug模式的包下的代码会打印debug日志,其他包还按照设置的默认级别如info打印日志。