SpringBoot中日志的使用log4j
项目中日志系统是必不可少的,目前比较流行的日志框架有 log4j
、logback
等,这两个框架的作者是同一个
人,Logback
旨在作为流行的 log4j
项目的后续版本,从而恢复 log4j
离开的位置。
另外 slf4j(Simple Logging Facade for Java)
则是一个日志门面框架,提供了日志系统中常用的接口,
logback
和 log4j
则对 slf4j
进行了实现。
官网:https://logging.apache.org/log4j/1.x/
SpringBoot 默认就是使用 SLF4J
作为日志门面,logback
作为日志实现来记录日志。
Spring Boot在所有内部日志中使用Commons Logging
,但也保留默认配置对常用日志的支持,如:
Java Util Logging, Log4J, Log4J2, SLF4J, Logback
每种 Logger 都可以通过配置使用控制台或者文件输出日志内容。
默认情况下,如果您使用 Starters
,会使用 Logback
来实现日志管理。
我们没必要纠结使用默认的 Logback
还是 Log4j
,直接用 Slf4j
即可。至于这个日志具体是如何写到控制台或
者文件的,则由Spring Boot项目中引入了什么具体的日志框架决定,默认情况下就是 Logback
。
我们本文将讲述如何在spring boot 中应用 logback+slf4j
实现日志的记录。
1、各个日志之间的关系
1.1 spring-boot-starter-logging
<dependency><artifactId>spring-boot-starter-logging</artifactId><groupId>org.springframework.boot</groupId>
</dependency>
org.springframework.boot
的依赖:
<dependencies><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.6</version><scope>compile</scope></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-to-slf4j</artifactId><version>2.14.1</version><scope>compile</scope></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jul-to-slf4j</artifactId><version>1.7.32</version><scope>compile</scope></dependency>
</dependencies>
1.2 spring-boot-starter
boot-starter-web 启动器当中,会依赖中我们所使用环境的一些 jar包的信息,里面就包含了slf4j
日志门面和
logback
的日志实现。
1.3 总结
1、SpringBoot底层默认使用 logback 作为日志实现
2、使用了 SLF4J 作为日志门面
3、将JUL也转换成 slf4j
4、在使用Springboot框架之后,其内部所有的日志实现都通过桥接器转换成slf4j日志门面进行统一的管理,最终
交给logback日志实现框架进行日志输出。
2、为什么使用logback
-
Logback 是log4j 框架的作者开发的新一代日志框架,它效率更高、能够适应诸多的运行环境,同时天然支持
SLF4J。
-
Logback的定制性更加灵活,同时也是spring boot的内置日志框架。
3、项目编写
3.1 添加依赖
maven依赖中添加了spring-boot-starter-logging
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId>
</dependency>
但是呢,实际开发中我们不需要直接添加该依赖,你会发现spring-boot-starter
其中包含了spring-boot-
starter-logging
,该依赖内容就是 Spring Boot 默认的日志框架Logback+SLF4J
。而spring-boot-starter-
web
包含了spring-boot-starte
,所以我们只需要引入web组件即可:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
完整 pom.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.6</version><relativePath/></parent><groupId>com.log</groupId><artifactId>spring-boot-log</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-boot-log</name><description>spring-boot-log</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
3.2 Controller编写
package com.log.controller;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author zhangshixing* @date 2021年11月04日 17:42*/
// 也可以使用@Slf4j注解输出日志(建议)
@RestController
public class DemoController {/*** 声明日志记录器对象(slf4j包)*/public static final Logger logger = LoggerFactory.getLogger(DemoController.class);@GetMapping("get")public void test() {logger.error("error");logger.warn("warn");logger.info("info");logger.debug("debug");logger.trace("trace");}
}
3.3 测试类
package com.log;import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class SpringBootLogApplicationTests {// 声明日志记录器对象(slf4j包)public static final Logger logger = LoggerFactory.getLogger(SpringBootLogApplicationTests.class);@Testvoid contextLoads() {logger.error("error");logger.warn("warn");logger.info("info");logger.debug("debug");logger.trace("trace");}
}
输出:
2023-11-18 10:17:19.458 ERROR 1596 --- [ main] com.log.SpringBootLogApplicationTests : error
2023-11-18 10:17:19.458 WARN 1596 --- [ main] com.log.SpringBootLogApplicationTests : warn
2023-11-18 10:17:19.458 INFO 1596 --- [ main] com.log.SpringBootLogApplicationTests : info
因为我们没有提供任何配置文件,因此默认的日志级别就是info,所以 debug 和 trace 不会输出。
4、基本配置
Springboot 支持对日志进行具体的配置,可以直接在 application.properties
配置文件中简单定义,也可以
导入具体日志实现的配置文件。
4.1 默认配置
4.1.1 日志输出文件配置
默认情况下Spring Boot将日志输出到控制台,不会写到日志文件。
如果要编写除控制台输出之外的日志文件,则需在
application.properties
中设置logging.file.name
或logging.file.path
属性。
注:二者不能同时使用,如若同时使用,则只有 logging.file.name 生效
-
logging.file.name
=文件名 -
logging.file.path
=日志文件路径 -
logging.level.包名
=指定包下的日志级别 -
logging.pattern.console
=日志打印规则
logging.file.name
设置文件,可以是绝对路径,也可以是相对路径。如:logging.file.name=my.log
logging.file.path
设置目录,会在该目录下创建spring.log
文件,并写入日志内容,如:
logging.file.path=/var/log
注:二者不能同时使用,如若同时使用,则只有
logging.file.name
生效,可以看到这种方式配置简单,但是能实现的功能也非常有限,如果想要更复杂的需求,就需要下面的定制化配置了。
我们设置:
logging.file.path=D:
会生成:
我们设置:
logging.file.path=D:
logging.file.name=D:\\my_log.txt
4.1.2 指定日志输出的级别、格式
# 自定义logger对象的日志级别,com.log.controller是自定义logger对象的名称,也就是包名
logging.level.com.log.controller = trace
# 指定控制台输出消息格式
# 格式配置请参考:https://logging.apache.org/log4j/2.x/manual/layouts.html
logging.pattern.console = [%-5level] %d{yyyy-MM-dd HH:mm:ss} %c [%thread] %m%n
发送请求:http://127.0.0.1:8080/get
输出:
[ERROR] 2023-11-18 21:24:04 com.log.controller.DemoController [http-nio-8080-exec-1] error
[WARN ] 2023-11-18 21:24:04 com.log.controller.DemoController [http-nio-8080-exec-1] warn
[INFO ] 2023-11-18 21:24:04 com.log.controller.DemoController [http-nio-8080-exec-1] info
[DEBUG] 2023-11-18 21:24:04 com.log.controller.DemoController [http-nio-8080-exec-1] debug
[TRACE] 2023-11-18 21:24:04 com.log.controller.DemoController [http-nio-8080-exec-1] trace
4.1.3 指定日志文件消息格式
# 指定日志文件消息格式
logging.pattern.file=[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c [%thread] %m%n
输出:
SpringBoot提供的默认配置文件无法进行复杂的配置,比如所有日志都放到一个文件当中,不易于后期维护和管
理,希望是按照一定的规则进行滚动拆分,比如文件大小,时间等。通过简单的SpringBoot提供的配置文件还不
够,通常在企业开发中会导入具体某个日志实现相应的配置文件。
给类路径下放上每个日志框架自己的配置文件,SpringBoot就不使用默认配置的了:
日志框架 | 配置文件 |
---|---|
Logback | logback-spring.xml、logback.xml |
Log4j2 | log4j2-spring.xml、log4j2.xml |
JUL | logging.properties |
4.2 logback-spring.xml说明
Spring Boot 官方推荐优先使用带有 -spring
的文件名作为你的日志配置(如使用logback-spring.xml
,而不
是 logback.xml
),命名为logback-spring.xml
的日志配置文件,将xml放至src/main/resource
下面。
也可以使用自定义的名称,比如logback-config.xml
,只需要在application.properties
文件中使用
logging.config=classpath:logback-config.xml
指定即可。
对于 logback 配置文件,logback-spring.xml
和 logback.xml
都能够被加载识别,增加了 -spring
的配置
文件会被 SpringBoot 框架解析,而不是由 logback 解析。
被 SpringBoot 框架解析的文件,只需修改 SpringBoot 的全局参数,就能对配置文件进行灵活调整,而不需要再
修改 logback 提供的核心配置文件了。
4.3 Logback架构
在讲解logback-spring.xml
之前我们先来了解三个单词:Logger
(记录器),Appenders
(附加器) 和
Layouts
(布局)。
Logback 的架构主要由三个核心组件组成:Logger、Appender 和 Layout。其中,Logger 用于记录 Log,
Appender 用于将 Log 输出到控制台或文件,Layout 用于定义 Log 输出格式。
这三种类型的组件协同工作,使开发人员能够根据消息类型和级别记录消息,并在运行时控制这些消息的格式以及
报告的位置。下面简要介绍一下这三个概念。
4.3.1 Logger
Logger 相当于一个记录器,用于产生 Log。Logger 有一个与之关联的 Log Level,表示记录 Log 要记录的最小等
级。Logger 可以选择是否记录它接收到的 Log,如果记录的 Log Level 低于 Logger 的 Log Level 则不记录。多个
Logger 可以形成一颗 Logger 的层次结构。
4.3.2 Appender
Appender 用于配置 Log 输出的目的地。Log 可以输出到控制台,文件,远程服务器等等。每个 Appender 都有
一个 Layout,用于格式化 Log 输出。一个 Logger 可以由多个 Appender 处理 Log 事件,例如,一个 Logger 可
以将所有 Error Level 的 Log 信息输出到一个文件中,同时将其他 Level 的 Log 输出到控制台。
4.3.3 Layout
Layout 用于格式化 Log 的输出方式。Layout 的作用是对 Log 进行格式化,然后由 Appender 输出。在 Layout
中可以定义 Log 的输出格式,比如时间,线程名称,Log Level 和 Log 的正文内容等。
4.3.4 Logback 配置文件
Logback 的配置文件使用 XML 格式编写,一般命名为 logback.xml
。配置文件中包括了 Logger、Appender 和
Encoder 等标签。下面是一个基本的 xml 配置文件的示例:
<configuration><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><!-- encoders are assigned the typech.qos.logback.classic.encoder.PatternLayoutEncoder by default --><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><logger name="chapters.configuration" level="INFO"/><!-- Strictly speaking, the level attribute is not necessary since --><!-- the level of the root level is set to DEBUG by default. --><root level="DEBUG"> <appender-ref ref="STDOUT" /></root> </configuration>
上面示例中,定义了一个名为 STDOUT
的 Appender,它是 ConsoleAppender 类型,用于将日志信息输出到控制
台上。同时定义了一个根 Logger,日志级别为 DEBUG,并将日志信息输出到 STDOUT
Appender 中。Encoder
标签用于定义日志信息的输出格式。
<?xml version="1.0" encoding="UTF-8" ?>
<configuration><!-- 配置集中管理属性作用:如果其他标签要使用,可以直接通过表达式来引用:${property的name值}--><!-- 1.配置日志的输出格式,name:自定义名称 value:具体格式值 --><property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c %M %L %thread %m %n"/><!-- 2.配置控制台输出的appender, name:自定义appender名称 class:appender类型--><appender name="myConsole" class="ch.qos.logback.core.ConsoleAppender"><!-- 2.1控制输出流对象,默认System.out控制台黑色字体,修改为System.err红色字体 --><target>System.err</target><!-- 2.2日志消息的格式 --><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><!-- 3.自定义logger 对象,additivity:是否继承父元素RootLogger的属性配置--><logger name="com.ahead" level="info" additivity="false"><appender-ref ref="myConsole" /></logger>
</configuration>
上传了具体日志实现的配置文件后,默认的SpringBoot配置信息就会作废。
4.3 <configuration>元素
logback.xml
配置文件的基本结构可以描述为<configuration>
元素,包含零个或多个<appender>
元素,后跟
零个或多个<logger>
元素,后跟最多一个<root>
元素(也可以没有)。
下图说明了这种基本结构:
4.4 <logger>元素
<logger>
元素只接受一个必需的name属性,一个可选的level属性和一个可选的additivity
属性,允许值为
true或false。level属性的值允许一个不区分大小写的字符串值TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF
。
特殊于大小写不敏感的值INHERITED
或其同义词NULL将强制记录器的级别从层次结构中的较高级别继承。
<logger>
元素可以包含零个或多个<appender-ref>
元素,这样引用的每个appender都被添加到指定的logger
中,logger元素级别具有继承性。
例1:示例中,仅为根记录器分配了级别。 此级别值DEBUG由其他记录器X,X.Y和X.Y.Z继承
Logger name | Assigned level | Effective level |
---|---|---|
root | DEBUG | DEBUG |
X | none | DEBUG |
X.Y | none | DEBUG |
X.Y.Z | none | DEBUG |
例2:所有记录器都有一个指定的级别值。 级别继承不起作用
Logger name | Assigned level | Effective level |
---|---|---|
root | ERROR | ERROR |
X | INFO | INFO |
X.Y | DEBUG | DEBUG |
X.Y.Z | WARN | WARN |
例3:记录器root,X和X.Y.Z分别被分配了DEBUG,INFO和ERROR级别。 Logger X.Y从其父X继承其级别值。
Logger name | Assigned level | Effective level |
---|---|---|
root | DEBUG | DEBUG |
X | INFO | INFO |
X.Y | none | INFO |
X.Y.Z | ERROR | ERROR |
例4:在示例4中,记录器root和X分别被分配了DEBUG和INFO级别。 记录器X.Y和X.Y.Z从其最近的父X继承其级别
值,该父级具有指定的级别。
Logger name | Assigned level | Effective level |
---|---|---|
root | DEBUG | DEBUG |
X | INFO | INFO |
X.Y | none | INFO |
X.Y.Z | none | INFO |
4.5 <root>元素
<root>
元素配置根记录器,它支持单个属性,即 level 属性。它不允许任何其他属性,因为 additivity 标志不适
用于根记录器。此外,由于根记录器已被命名为 ROOT,因此它也不允许使用 name 属性。
level 属性的值可以是不区分大小写的字符串 TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF
之一。
<root>
元素可以包含零个或多个<appender-ref>
元素,这样引用的每个 appender 都被添加到根记录器中。
4.6 <appender>元素
appender使用<appender>
元素配置,该元素采用两个必需属性 name 和 class。name 属性指定 appender 的名
称,而 class 属性指定要实例化的 appender 类的完全限定名称。
<appender>
元素可以包含零个或一个<layout>
元素,零个或多个<encoder>
元素以及零个或多个<filter>
元
素,下图说明了常见的结构:
重要:在logback中,输出目标称为appender
,addAppender
方法将appender
添加到给定的记录器logger。给
定记录器的每个启用的日志记录请求都将转发到该记录器中的所有appender
以及层次结构中较高的appender
。
换句话说,appender
是从记录器层次结构中附加地继承的。
例如,如果将控制台appender
添加到根记录器,则所有启用的日志记录请求将至少在控制台上打印。如果另外将
文件追加器添加到记录器(例如L),则对L和L的子项启用的记录请求将打印在文件和控制台上。通过将记录器的
additivity
标志设置为false,可以覆盖此默认行为,以便不再添加appender
累积。
Appender
是一个接口,它有许多子接口和实现类,具体如下图所示:
其中最重要的两个Appender为:ConsoleAppender
、RollingFileAppender
。
4.6.1 ConsoleAppender
ConsoleAppender
,如名称所示,将日志输出到控制台上。
4.6.2 RollingFileAppender
RollingFileAppender
是FileAppender
的一个子类,扩展了FileAppender
,具有翻转日志文件的功能。例
如RollingFileAppender
可以记录到名为log.txt
文件的文件,并且一旦满足某个条件,就将其日志记录目标
更改为另一个文件。
有两个与RollingFileAppender
交互的重要子组件。第一个RollingFileAppender
子组件,即RollingPolicy
负责执行翻转所需的操作。RollingFileAppender
的第二个子组件,即TriggeringPolicy
将确定是否以及何时
发生翻转。因此,RollingPolicy
负责什么和TriggeringPolicy
负责什么时候。
作为任何用途,RollingFileAppender
必须同时设置RollingPolicy
和TriggeringPolicy
。但是,如果其
RollingPolicy
也实现了TriggeringPolicy
接口,则只需要显式指定前者。
滚动策略:
-
TimeBasedRollingPolicy
:可能是最受欢迎的滚动策略。它根据时间定义翻转策略,例如按天或按月。TimeBasedRollingPolicy
承担滚动和触发所述翻转的责任。实际上,TimeBasedTriggeringPolicy
实现了
RollingPolicy
和TriggeringPolicy
接口。 -
SizeAndTimeBasedRollingPolicy
:有时您可能希望按日期归档文件,但同时限制每个日志文件的大小,特别是如果后处理工具对日志文件施加大小限制。为了满足此要求,logback 提供了
SizeAndTimeBasedRollingPolicy
,它是TimeBasedRollingPolicy
的一个子类,实现了基于时间和日志文件大小的翻滚策略。
4.6.3 <encoder>元素
encoder中最重要就是pattern属性,它负责控制输出日志的格式,这里给出一个我自己写的示例:
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) --- [%15.15(%thread)] %cyan(%-40.40(%logger{40})) : %msg%n</pattern>
其中:
# 日期
%d{yyyy-MM-dd HH:mm:ss.SSS}# 日志级别
%-5level# 颜色,info为蓝色,warn为浅红,error为加粗红,debug为黑色
%highlight()# 打印日志的线程
%thread# 如果记录的线程字符长度小于15(第一个)则用空格在左侧补齐,如果字符长度大于15(第二个),则从开头开始截断多余的字符
%15.15()# 颜色
%cyan# 日志输出的类名
# 表示logger名字最长40个字符,否则按照句点分割。
%logger{40}# 如果记录的logger字符长度小于40(第一个)则用空格在右侧补齐,如果字符长度大于40(第二个),则从开头开始截断多余的字符
%-40.40()# 日志输出内容
%msg# 换行符
%n
格式配置请参考:https://logging.apache.org/log4j/2.x/manual/layouts.html
4.6.4 <filter>元素
filter中最重要的两个过滤器为:LevelFilter
、ThresholdFilter
。
LevelFilter
根据精确的级别匹配过滤事件。如果事件的级别等于配置的级别,则筛选器接受或拒绝该事件,具
体取决于onMatch
和onMismatch
属性的配置。例如下面配置将只打印INFO级别的日志,其余的全部禁止打印输
出:
<configuration><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>INFO</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter><encoder><pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern></encoder></appender><root level="DEBUG"><appender-ref ref="CONSOLE" /></root>
</configuration>
ThresholdFilter
过滤低于指定阈值的事件。对于等于或高于阈值的事件,ThresholdFilter
将在调用其
decision()
方法时响应NEUTRAL
。
但是,将拒绝级别低于阈值的事件,例如下面的配置将拒绝所有低于INFO级别的日志,只输出INFO以及以上级别
的日志:
<configuration><appender name="CONSOLE"class="ch.qos.logback.core.ConsoleAppender"><!-- deny all events with a level below INFO, that is TRACE and DEBUG --><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>INFO</level></filter><encoder><pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern></encoder></appender><root level="DEBUG"><appender-ref ref="CONSOLE" /></root>
</configuration>
5、详细的logback-spring.xml示例1
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL, 如果设置为WARN, 则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时, 配置文档如果发生改变, 将会被重新加载, 默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔, 如果没有给出时间单位, 默认单位是毫秒, 当scan为true时, 此属性生效, 默认的时间间隔为1分钟 -->
<!-- debug:当此属性设置为true时, 将打印出logback内部日志信息, 实时查看logback运行状态, 默认值为false -->
<configuration scan="true" scanPeriod="10 seconds"><contextName>spring-boot-log</contextName><!-- 彩色日志 --><!-- 彩色日志依赖的渲染类 --><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" /><!-- 变量定义begin--><!-- 使用spring.application.name设置的名字 --><springProperty scope="context" name="APP_NAME" source="spring.application.name"/><!-- 定义日志存储的路径,建议不要配置相对路径 --><property name="FILE_DIR" value="D:\\logs\\${APP_NAME}" /><!-- 设置全局属性,通过获取变量的形式${APP_NAME} --><property name="ROLL_FILE_DIR" value="D:\\logs\\${APP_NAME}" /><!-- 彩色日志格式 --><property name="CONSOLE_LOG_FORMAT" 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}}"/><!--默认日志格式: 时间日期 -> 日志级别 -> 线程ID -> 分隔符 -> 线程名 -> Logger名(通常对应的是类名) -> 日志内容 --><!-- 格式化输出:%date表示日期, %thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息, %n是换行符--><property name="LOG_FORMAT" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" /><!-- 变量定义end--><!-- 日志输出方式定义 begin --><!--1、输出到控制台--><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><!--此日志appender是为开发使用, 只配置最低级别, 控制台输出的日志级别是大于或等于此级别的日志信息--><!-- 日志级别过滤DEBUG以下 --><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>DEBUG</level></filter><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!-- 如果是开发环境,使用默认的消息格式 --><springProfile name="dev"><pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5level] %m%n</pattern></springProfile><!-- 如果是生产环境,使用简单的消息格式输出消息 --><springProfile name="pro"><!-- 按照上面配置的LOG_FORMAT来打印日志 --><pattern>${CONSOLE_LOG_FORMAT}</pattern><!-- 设置字符集 --><charset>UTF-8</charset></springProfile></encoder></appender><!-- 2、输出到文件 --><!-- 输出到文件, 这种方式是单个日志文件保存, 文件会不停的增大, 除非手动删除 --><appender name="FILE" class="ch.qos.logback.core.FileAppender"><file>${FILE_DIR}\\spring-log.log</file><append>true</append><encoder><!-- 按照上面配置的LOG_FORMAT来打印日志 --><pattern>${LOG_FORMAT}</pattern></encoder></appender><!-- 3、滚动输出到文件 --><!-- 滚动日志输出,每天生成一个日志文件,保存30天的日志文件,FILE用来切分文件的 --><appender name="FILE_ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 当前记录的日志文档完整路径 --><file>${ROLL_FILE_DIR}\\spring-log-rolling.log</file><!--日志文档输出格式--><encoder><!-- 按照上面配置的LOG_FORMAT来打印日志 --><pattern>${LOG_FORMAT}</pattern><!-- 此处设置字符集 --><charset>UTF-8</charset></encoder><!--日志滚动策略,按照时间、按大小滚动记录--><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${ROLL_FILE_DIR}\\spring-log-rolling.%d{yyyy-MM-dd}.%i.log</fileNamePattern><!-- 只保留30天的日志(非持续运行情况下,30天外不会清理)--><maxHistory>30</maxHistory><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><!-- 日志文件的最大大小 --><maxFileSize>100MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy><!-- 应对服务非持续偶尔运行,日志清理机制无法触发而导致日志得不到清理的情况--><!-- 超出删除老文件 --><totalSizeCap>500MB</totalSizeCap><cleanHistoryOnStart>true</cleanHistoryOnStart></rollingPolicy><!-- 以上的配置是当日志文件的大小达到100MB时,就新建一个日志文件,当滚动日志所占控件总和超过500MB时,就将最老的日志文件删除掉最多保存30天的日志文件,超过30天也会将最老的日志文件删除需要注意的是,如果日志文件比较大,如果1个小时就创建了5个日志文件,每个100MB,那下一个小时重新生成的日志文件会将上一个小时的日志文件覆盖掉,而且由于日志文件大小总和超过500MB,所以实际无法保存30天的日志文件,所以需要根据实际项目确定以上参数该怎么设置--></appender><!-- 日志输出方式定义 end --><!-- <logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender><logger>仅有一个name属性,一个可选的level和一个可选的addtivity属性name:用来指定受此logger约束的某一个包或者具体的某一个类level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别如果未设置此属性,那么当前logger将会继承上级的级别addtivity:是否向上级logger传递打印信息,默认是true--><!--root节点是必选节点,用来指定通用的日志输出级别,只有一个level属性level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF不能设置为INHERITED或者同义词NULL,默认是DEBUG可以包含零个或多个元素,标识这个appender将会添加到这个logger--><!-- 日志输出级别 begin--><!-- cloud环境下,去掉nacos的日志打印信息 --><!--<logger name="com.alibaba.nacos" level="OFF" addtivity="false"> </logger>--><!-- 打印info级别的信息 --><!--<root level="INFO"><appender-ref ref="FILE"/></root>--><!-- 控制整个项目的日志级别 --><root level="info"><!--使用info级别输出日志到控制台、文件及滚动文件--><!--采用上面定义的日志输出方式确定本项目究竟将日志输出到什么地方--><!--输出到终端--><appender-ref ref="CONSOLE" /><!--输出到文件--><appender-ref ref="FILE" /><!--输出到文件,滚动输出,避免单个文件过大,通常采用这种方式--><appender-ref ref="FILE_ROLLING" /></root><!-- 日志输出级别 end--><!--如果采用root定义,则是所有包的日志都会打印,如果要控制只需要当前的包,则使用下面的logger的标签定义name表示是打印哪个包下面的level表示这个包下面什么级别的日志打印出来--><!--<logger name="com.log.controller" level="debug"><appender-ref ref="CONSOLE"/><appender-ref ref="FILE"/><appender-ref ref="FILE_ROLLING" /></logger>--><!-- 本地环境输出至控制台 --><!-- 如果使用了 springProfile, 需要将logback.xml名称改为logback-spring.xml--><!--<springProfile name="dev"><root level="DEBUG"><appender-ref ref="CONSOLE" /><appender-ref ref="FILE" /></root></springProfile>-->
</configuration>
使用是需要设置:
spring.profiles.active = dev/pro
6、详细的logback-spring.xml示例2
<?xml version="1.0" encoding="UTF-8"?> <!-- 从高到地低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
<!-- 日志输出规则 根据当前ROOT 级别,日志输出时,级别高于root默认的级别时 会输出 -->
<!-- 以下 每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志--> <!-- 属性描述 scan:性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false"> <!-- 定义日志文件 输入位置 --> <property name="log_dir" value="/customize/logs" /> <!-- 日志最大的历史 30天 --> <property name="maxHistory" value="30"/> <!-- ConsoleAppender 控制台输出日志 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- 对日志进行格式化 --> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger -%msg%n</pattern> </encoder> </appender> <!-- ERROR级别日志 --> <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender--> <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 过滤器,只记录WARN级别的日志 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--日志输出位置 可相对、和绝对路径 --> <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/error-log.log</fileNamePattern> <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>是6, 则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除--> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <!-- 按照固定窗口模式生成日志文件,当文件大于20MB时,生成新的日志文件。窗口大小是1到3,当保存了3个归档文件后,将覆盖最早的日志。 <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/.log.zip</fileNamePattern> <minIndex>1</minIndex> <maxIndex>3</maxIndex> </rollingPolicy> --> <!-- 查看当前活动文件的大小,如果超过指定大小会告知RollingFileAppender 触发当前活动文件滚动 <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <maxFileSize>5MB</maxFileSize> </triggeringPolicy> --> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern> </encoder> </appender> <!-- WARN级别日志 appender --> <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 过滤器,只记录WARN级别的日志 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>WARN</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 按天回滚 daily --> <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/warn-log.log </fileNamePattern> <!-- 日志最大的历史 60天 --> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern> </encoder> </appender> <!-- INFO级别日志 appender --> <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 过滤器,只记录INFO级别的日志 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 按天回滚 daily --> <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/info-log.log </fileNamePattern> <!-- 日志最大的历史 60天 --> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern> </encoder> </appender> <!-- DEBUG级别日志 appender --> <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 过滤器,只记录DEBUG级别的日志 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 按天回滚 daily --> <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/debug-log.log </fileNamePattern> <!-- 日志最大的历史 60天 --> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern> </encoder> </appender> <!-- TRACE级别日志 appender --> <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 过滤器,只记录ERROR级别的日志 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>TRACE</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 按天回滚 daily --> <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/trace-log.log </fileNamePattern> <!-- 日志最大的历史 60天 --> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern> </encoder> </appender> <logger name="java.sql.PreparedStatement" value="DEBUG" /> <logger name="java.sql.Connection" value="DEBUG" /> <logger name="java.sql.Statement" value="DEBUG" /> <logger name="com.ibatis" value="DEBUG" /> <logger name="com.ibatis.common.jdbc.SimpleDataSource" value="DEBUG" /> <logger name="com.ibatis.common.jdbc.ScriptRunner" level="DEBUG"/> <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" value="DEBUG" /> <!-- root级别 DEBUG --> <root level="debug"> <!-- 控制台输出 --> <appender-ref ref="STDOUT" /> <!-- 文件输出 --> <appender-ref ref="ERROR" /> <appender-ref ref="INFO" /> <appender-ref ref="WARN" /> <appender-ref ref="DEBUG" /> <appender-ref ref="TRACE" /> </root>
</configuration>
7、详细的logback-spring.xml示例3
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true"><!-- appender是configuration的子节点,是负责写日志的组件。 --><!-- ConsoleAppender:把日志输出到控制台 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><!-- 默认情况下,每个日志事件都会立即刷新到基础输出流。 这种默认方法更安全,因为如果应用程序在没有正确关闭appender的情况下退出,则日志事件不会丢失。但是,为了显着增加日志记录吞吐量,您可能希望将immediateFlush属性设置为false --><!--<immediateFlush>true</immediateFlush>--><encoder><!-- %37():如果字符没有37个字符长度,则左侧用空格补齐 --><!-- %-37():如果字符没有37个字符长度,则右侧用空格补齐 --><!-- %15.15():如果记录的线程字符长度小于15(第一个)则用空格在左侧补齐,如果字符长度大于15(第二个),则从开头开始截断多余的字符 --><!-- %-40.40():如果记录的logger字符长度小于40(第一个)则用空格在右侧补齐,如果字符长度大于40(第二个),则从开头开始截断多余的字符 --><!-- %msg:日志打印详情 --><!-- %n:换行符 --><!-- %highlight():转换说明符以粗体红色显示其级别为ERROR的事件,红色为WARN,BLUE为INFO,以及其他级别的默认颜色。 --><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) --- [%15.15(%thread)] %cyan(%-40.40(%logger{40})) : %msg%n</pattern><!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 --><charset>UTF-8</charset></encoder></appender><!-- info 日志--><!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 --><!-- 以下的大概意思是:1.先按日期存日志,日期变了,将前一天的日志文件名重命名为XXX%日期%索引,新的日志仍然是project_info.log --><!-- 2.如果日期没有发生变化,但是当前日志的文件大小超过10MB时,对当前日志进行分割 重命名--><appender name="info_log" class="ch.qos.logback.core.rolling.RollingFileAppender"><!--日志文件路径和名称--><File>logs/project_info.log</File><!--是否追加到文件末尾,默认为true--><append>true</append><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>DENY</onMatch><!-- 如果命中ERROR就禁止这条日志 --><onMismatch>ACCEPT</onMismatch><!-- 如果没有命中就使用这条规则 --></filter><!--有两个与RollingFileAppender交互的重要子组件。 第一个RollingFileAppender子组件,即RollingPolicy:负责执行翻转所需的操作。RollingFileAppender的第二个子组件,即TriggeringPolicy:将确定是否以及何时发生翻转。 因此,RollingPolicy负责什么和TriggeringPolicy负责什么时候.作为任何用途,RollingFileAppender必须同时设置RollingPolicy和TriggeringPolicy,但是,如果其RollingPolicy也实现了TriggeringPolicy接口,则只需要显式指定前者。--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 日志文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 --><!-- 文件名:logs/project_info.2017-12-05.0.log --><!-- 注意:SizeAndTimeBasedRollingPolicy中 %i和%d令牌都是强制性的,必须存在,要不会报错 --><fileNamePattern>logs/project_info.%d.%i.log</fileNamePattern><!-- 每产生一个日志文件,该日志文件的保存期限为30天, ps:maxHistory的单位是根据fileNamePattern中的翻转策略自动推算出来的,例如上面选用了yyyy-MM-dd,则单位为天如果上面选用了yyyy-MM,则单位为月,另外上面的单位默认为yyyy-MM-dd--><maxHistory>30</maxHistory><!-- 每个日志文件到10mb的时候开始切分,最多保留30天,但最大到20GB,哪怕没到30天也要删除多余的日志 --><totalSizeCap>20GB</totalSizeCap><!-- maxFileSize:这是活动文件的大小,默认值是10MB,测试时可改成5KB看效果 --><maxFileSize>10MB</maxFileSize></rollingPolicy><!--编码器--><encoder><!-- pattern节点,用来设置日志的输入格式 ps:日志文件中没有设置颜色,否则颜色部分会有ESC[0:39em等乱码--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%15.15(%thread)] %-40.40(%logger{40}) : %msg%n</pattern><!-- 记录日志的编码:此处设置字符集 - --><charset>UTF-8</charset></encoder></appender><!-- error 日志--><!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 --><!-- 以下的大概意思是:1.先按日期存日志,日期变了,将前一天的日志文件名重命名为XXX%日期%索引,新的日志仍然是project_error.log --><!-- 2.如果日期没有发生变化,但是当前日志的文件大小超过10MB时,对当前日志进行分割 重命名--><appender name="error_log" class="ch.qos.logback.core.rolling.RollingFileAppender"><!--日志文件路径和名称--><File>logs/project_error.log</File><!--是否追加到文件末尾,默认为true--><append>true</append><!-- ThresholdFilter过滤低于指定阈值的事件。 对于等于或高于阈值的事件,ThresholdFilter将在调用其decision()方法时响应NEUTRAL。 但是,将拒绝级别低于阈值的事件 --><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>ERROR</level><!-- 低于ERROR级别的日志(debug,info)将被拒绝,等于或者高于ERROR的级别将相应NEUTRAL --></filter><!--有两个与RollingFileAppender交互的重要子组件。 第一个RollingFileAppender子组件,即RollingPolicy:负责执行翻转所需的操作。RollingFileAppender的第二个子组件,即TriggeringPolicy:将确定是否以及何时发生翻转。 因此,RollingPolicy负责什么和TriggeringPolicy负责什么时候.作为任何用途,RollingFileAppender必须同时设置RollingPolicy和TriggeringPolicy,但是,如果其RollingPolicy也实现了TriggeringPolicy接口,则只需要显式指定前者。--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 活动文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 --><!-- 文件名:logs/project_error.2017-12-05.0.log --><!-- 注意:SizeAndTimeBasedRollingPolicy中 %i和%d令牌都是强制性的,必须存在,要不会报错 --><fileNamePattern>logs/project_error.%d.%i.log</fileNamePattern><!-- 每产生一个日志文件,该日志文件的保存期限为30天, ps:maxHistory的单位是根据fileNamePattern中的翻转策略自动推算出来的,例如上面选用了yyyy-MM-dd,则单位为天如果上面选用了yyyy-MM,则单位为月,另外上面的单位默认为yyyy-MM-dd--><maxHistory>30</maxHistory><!-- 每个日志文件到10mb的时候开始切分,最多保留30天,但最大到20GB,哪怕没到30天也要删除多余的日志 --><totalSizeCap>20GB</totalSizeCap><!-- maxFileSize:这是活动文件的大小,默认值是10MB,测试时可改成5KB看效果 --><maxFileSize>10MB</maxFileSize></rollingPolicy><!--编码器--><encoder><!-- pattern节点,用来设置日志的输入格式 ps:日志文件中没有设置颜色,否则颜色部分会有ESC[0:39em等乱码--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%15.15(%thread)] %-40.40(%logger{40}) : %msg%n</pattern><!-- 记录日志的编码:此处设置字符集 - --><charset>UTF-8</charset></encoder></appender><!--给定记录器的每个启用的日志记录请求都将转发到该记录器中的所有appender以及层次结构中较高的appender(不用在意level值)。换句话说,appender是从记录器层次结构中附加地继承的。例如,如果将控制台appender添加到根记录器,则所有启用的日志记录请求将至少在控制台上打印。如果另外将文件追加器添加到记录器(例如L),则对L和L'子项启用的记录请求将打印在文件和控制台上。通过将记录器的additivity标志设置为false,可以覆盖此默认行为,以便不再添加appender累积--><!-- configuration中最多允许一个root,别的logger如果没有设置级别则从父级别root继承 --><root level="INFO"><appender-ref ref="STDOUT" /></root><!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 --><!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE --><logger name="com.sailing.springbootmybatis" level="INFO"><appender-ref ref="info_log" /><appender-ref ref="error_log" /></logger><!-- 利用logback输入mybatis的sql日志,注意:如果不加 additivity="false" 则此logger会将输出转发到自身以及祖先的logger中,就会出现日志文件中sql重复打印--><logger name="com.sailing.springbootmybatis.mapper" level="DEBUG" additivity="false"><appender-ref ref="info_log" /><appender-ref ref="error_log" /></logger><!-- additivity=false代表禁止默认累计的行为,即com.atomikos中的日志只会记录到日志文件中,不会输出层次级别更高的任何appender--><logger name="com.atomikos" level="INFO" additivity="false"><appender-ref ref="info_log" /><appender-ref ref="error_log" /></logger>
</configuration>
8、使用注意事项
8.1 日志级别判断
这里再说下 log 日志输出代码,一般有人可能在代码中使用如下方式输出:
Object entry = new SomeObject();
logger.debug("The entry is " + entry);
上面看起来没什么问题,但是会存在构造消息参数的成本,即将entry转换成字符串相加。
并且无论是否记录消息,都是如此,即:哪怕日志级别为 INFO,也会执行括号里面的操作,但是日志不会输出,
下面是优化后的写法:
if(logger.isDebugEnabled()) { Object entry = new SomeObject(); logger.debug("The entry is " + entry);
}
上面的写法,首先对设置的日志级别进行了判断,如果为debug模式,才进行参数的构造,对第一种写法进行
了改善。
8.2 占位符
不过还有最好的写法,使用占位符:
Object entry = new SomeObject();
logger.debug("The entry is {}.", entry);
只有在评估是否记录之后,并且只有在决策是肯定的情况下,记录器实现才会格式化消息并将{}
对替换为条目
的字符串值。换句话说,当禁用日志语句时,此表单不会产生参数构造的成本。
logback 作者进行测试得出:第一种和第三种写法将产生完全相同的输出。但是,在禁用日志记录语句的情况下,
第三个变体将比第一个变体优于至少30倍。
如果有多个参数,写法如下:
logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);
如果需要传递三个或更多参数,则还可以使用Object []
变体:
Object[] paramArray = {newVal, below, above};
logger.debug("Value {} was inserted between {} and {}.", paramArray);
记录日志的时候我们可能需要在文件中记录下异常的堆栈信息,经过测试,logger.error(e)
不会打印出堆
栈信息,正确的写法是:
logger.error("程序异常, 详细信息:{}", e.getLocalizedMessage() , e);
我们可以看到 info 的多个重载函数: