SpringBoot中日志的使用log4j

SpringBoot中日志的使用log4j

项目中日志系统是必不可少的,目前比较流行的日志框架有 log4jlogback 等,这两个框架的作者是同一个

人,Logback 旨在作为流行的 log4j 项目的后续版本,从而恢复 log4j 离开的位置。

另外 slf4j(Simple Logging Facade for Java) 则是一个日志门面框架,提供了日志系统中常用的接口,

logbacklog4j 则对 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.namelogging.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就不使用默认配置的了:

日志框架配置文件
Logbacklogback-spring.xml、logback.xml
Log4j2log4j2-spring.xml、log4j2.xml
JULlogging.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.xmllogback.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 nameAssigned levelEffective level
rootDEBUGDEBUG
XnoneDEBUG
X.YnoneDEBUG
X.Y.ZnoneDEBUG

例2:所有记录器都有一个指定的级别值。 级别继承不起作用

Logger nameAssigned levelEffective level
rootERRORERROR
XINFOINFO
X.YDEBUGDEBUG
X.Y.ZWARNWARN

例3:记录器root,X和X.Y.Z分别被分配了DEBUG,INFO和ERROR级别。 Logger X.Y从其父X继承其级别值。

Logger nameAssigned levelEffective level
rootDEBUGDEBUG
XINFOINFO
X.YnoneINFO
X.Y.ZERRORERROR

例4:在示例4中,记录器root和X分别被分配了DEBUG和INFO级别。 记录器X.Y和X.Y.Z从其最近的父X继承其级别

值,该父级具有指定的级别。

Logger nameAssigned levelEffective level
rootDEBUGDEBUG
XINFOINFO
X.YnoneINFO
X.Y.ZnoneINFO

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中,输出目标称为appenderaddAppender方法将appender添加到给定的记录器logger。给

定记录器的每个启用的日志记录请求都将转发到该记录器中的所有appender以及层次结构中较高的appender

换句话说,appender是从记录器层次结构中附加地继承的。

例如,如果将控制台appender添加到根记录器,则所有启用的日志记录请求将至少在控制台上打印。如果另外将

文件追加器添加到记录器(例如L),则对L和L的子项启用的记录请求将打印在文件和控制台上。通过将记录器的

additivity标志设置为false,可以覆盖此默认行为,以便不再添加appender累积。

Appender是一个接口,它有许多子接口和实现类,具体如下图所示:

在这里插入图片描述

其中最重要的两个Appender为:ConsoleAppenderRollingFileAppender

4.6.1 ConsoleAppender

ConsoleAppender,如名称所示,将日志输出到控制台上。

4.6.2 RollingFileAppender

RollingFileAppenderFileAppender的一个子类,扩展了FileAppender,具有翻转日志文件的功能。例

RollingFileAppender可以记录到名为log.txt文件的文件,并且一旦满足某个条件,就将其日志记录目标

更改为另一个文件。

有两个与RollingFileAppender交互的重要子组件。第一个RollingFileAppender子组件,即RollingPolicy

负责执行翻转所需的操作。RollingFileAppender的第二个子组件,即TriggeringPolicy将确定是否以及何时

发生翻转。因此,RollingPolicy负责什么和TriggeringPolicy负责什么时候。

作为任何用途,RollingFileAppender必须同时设置RollingPolicyTriggeringPolicy。但是,如果其

RollingPolicy也实现了TriggeringPolicy接口,则只需要显式指定前者。

滚动策略:

  • TimeBasedRollingPolicy:可能是最受欢迎的滚动策略。它根据时间定义翻转策略,例如按天或按月。

    TimeBasedRollingPolicy承担滚动和触发所述翻转的责任。实际上,TimeBasedTriggeringPolicy

    现了RollingPolicyTriggeringPolicy接口。

  • 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中最重要的两个过滤器为:LevelFilterThresholdFilter

LevelFilter根据精确的级别匹配过滤事件。如果事件的级别等于配置的级别,则筛选器接受或拒绝该事件,具

体取决于onMatchonMismatch属性的配置。例如下面配置将只打印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 的多个重载函数:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/197734.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【React】React 基础

1. 搭建环境 npx create-react-app react-basic-demo2. 基本使用 JSX 中使用 {} 识别 JavaScript 中的表达式&#xff0c;比如变量、函数调用、方法调用等。 if、switch、变量声明等属于语句&#xff0c;不是表达式。 列表渲染使用 map 。 事件绑定用&#xff1b;on 事件名称…

Azure Machine Learning - Azure AI 搜索中的集成数据分块和嵌入

在基于索引器的索引编制中&#xff0c;Azure AI _集成矢量化_将数据分块和文本到矢量嵌入添加到技能中&#xff0c;它还为查询添加文本到矢量的转换。 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本…

webstorm/idea配置leetcode刷题

File -> settings -> Plugins -> 搜索leetcode 安装插件&#xff08;截图显示我已经安装过了&#xff09;&#xff0c;安装完成后点击OK操作&#xff0c;在编辑器四个边角就会出现一个leetcode的插件 File -> settings -> Tools-> Leetcode plugin 点击…

[C/C++]数据结构 栈和队列()

一:栈 1.1 栈的概念及结构 栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作,进行数据插入和删除操作的一端称为栈顶,另一端称为栈底,栈中的数据元素遵守先进后出的原则. 压栈:栈的插入操作叫做进栈/压栈/入栈,将数据插入栈顶 出栈:栈的删除操作也叫出…

正版软件|Soundop 专业音频编辑器,实现无缝的音频制作工作流程

关于Soundop Soundop 音频编辑器 直观而专业的音频编辑软件&#xff0c;用于录制、编辑、混合和掌握音频内容。 Soundop 是一款适用于 Windows 的专业音频编辑器&#xff0c;可在具有高级功能的直观灵活的工作区中录制、编辑和掌握音频并混音轨道。音频文件编辑器支持波形和频谱…

Unity 场景烘培 ——unity Post-Processing后处理1(四)

提示&#xff1a;文章有错误的地方&#xff0c;还望诸位大神不吝指教&#xff01; 文章目录 前言一、Post-Processing是什么&#xff1f;二、安装使用Post-Processing1.安装Post-Processing2.使用Post-Processing&#xff08;1&#xff09;.添加Post-process Volume&#xff08…

车载通信架构 —— 新车载总线类型下(以太网)的通信架构

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的人和事&#xff0c;多看一眼都是你的不…

java拼图游戏(待优化)

启动类 package com.yx.ui;public class App { //启动入口public static void main(String[] args) {//如果想要开启一个界面&#xff0c;就创建谁的对象 // new DengJFrame(); // new ZCJFrame();new GameJFrame();}}游戏类 package com.yx.ui;import java.awt.event.KeyEv…

嵌入式 Linux 移植与系统启动方法

1、Linux系统启动与U-Boot 所谓移植就是把程序代码从一种运行环境转移到另一种运行环境。对于内核移植来说&#xff0c;主要是从一种硬件平台转移到另一种硬件平台上运行。 体系结构级别的移植是指在不同体系结构平台上Linux内核的移植&#xff0c;例如&#xff0c;在ARM、MI…

Evil靶场

Evil 1.主机发现 使用命令探测存活主机&#xff0c;80.139是kali的地址&#xff0c;所以靶机地址就是80.134 fping -gaq 192.168.80.0/242.端口扫描 开放80&#xff0c;22端口 nmap -Pn -sV -p- -A 192.168.80.1343.信息收集 访问web界面 路径扫描 gobuster dir -u http…

ForkLift:macOS文件管理器/FTP客户端

ForkLift 是一款macOS下双窗口的文件管理器&#xff0c;可以代替本地的访达。ForkLift同时具备连接Ftp、SFtp、WebDav以及云服务器。 ForkLift还具备访达不具备的小功能&#xff0c;比如从文件夹位置打开终端&#xff0c;显示隐藏文件&#xff0c;制作替换等功能。ForkLift 是一…

解决k8s node节点报错: Failed to watch *v1.Secret: unknown

现象&#xff1a; 这个现象是发生在k8s集群证书过期&#xff0c;重新续签证书以后。 记得master节点的/etc/kubernetes/kubelet.conf文件已经复制到node节点了。 但是为什么还是报这个错&#xff0c;然后运行证书检查命令看一下&#xff1a; 看样子是差/etc/kubernetes/pki/…

八股文-TCP的四次挥手

TCP&#xff08;Transmission Control Protocol&#xff09;是一种面向连接的、可靠的传输协议&#xff0c;它的连接的建立和关闭过程都是经过精心设计的。在TCP连接关闭时&#xff0c;使用四次挥手来保证数据的完整传输和连接的正常终止。 漫画TCP的四次挥手 第一次挥手&#…

redis安装(Windows和linux)

如何实现Redis安装与使用的详细教程 Redis 简介 Redis是一个使用C语言编写的开源、高性能、非关系型的键值对存储数据库。它支持多种数据结构&#xff0c;包括字符串、列表、集合、有序集合、哈希表等。Redis的内存操作能力极强&#xff0c;其读写性能非常优秀&#xff0c;且…

PyCharm:PyCharm新建.py文件时自动带出指定内容

在pycharm中加上指定内容&#xff0c;每次新建.py文件都会自动带出指定内容 操作&#xff1a; File—Setting—Editor----File and Code Templates--Python Script 在右侧窗口中加上如下信息 # encoding: utf-8 # author: Jeffrey # file: ${NAME}.py # time: ${DATE} ${TI…

ControlNet原理及应用

《Adding Conditional Control to Text-to-Image Diffusion Models》 目录 1.背景介绍 2.原理详解 2.1 Controlnet 2.2 用于Stable Diffusion的ControlNet 2.3 训练 2.4 推理 3.实验结果 3.1 定性结果 3.2 消融实验 3.3 和之前结果比较 3.4 数据集大小的影响 4.结…

聚观早报 |联想集团Q2财季业绩;小鹏汽车Q3营收

【聚观365】11月17日消息 联想集团Q2财季业绩 小鹏汽车Q3营收 微软发布两款自研AI芯片 FAA批准SpaceX再次发射星际飞船 2023 OPPO开发者大会 联想集团Q2财季业绩 全球数字经济领导企业联想集团公布截至2023年9月30日的2023/24财年第二财季业绩&#xff1a;整体营收达到10…

【ARM Trace32(劳特巴赫) 使用介绍 2.2 -- TRACE32 进阶命令之 DIAG 弹框命令】

请阅读【ARM Coresight SoC-400/SoC-600 专栏导读】 上篇文章&#xff1a;【ARM Trace32(劳特巴赫) 使用介绍 2.1 – TRACE32 Practice 脚本 cmm 脚本学习】 下篇文章&#xff1a;【ARM Trace32(劳特巴赫) 使用介绍 3 - trace32 访问运行时的内存】 文章目录 DIALOG.OK 命令DIA…

react之基于@reduxjs/toolkit使用react-redux

react之基于reduxjs/toolkit使用react-redux 一、配置基础环境二、使用React Toolkit 创建 counterStore三、为React注入store四、React组件使用store中的数据五、实现效果六、提交action传递参数七、异步状态操作 一、配置基础环境 1.使用cra快速创建一个react项目 npx crea…

持续集成交付CICD:Jenkins Sharedlibrary 共享库

目录 一、理论 1.共享库 2.共享库配置 3.使用共享库 4.共享库扩展 二、实验 1.连接共享库 2.使用共享库 三、问题 1.路径报错 2.readJSON 报错 一、理论 1.共享库 &#xff08;1&#xff09;概念 1&#xff09;共享库这并不是一个全新的概念&#xff0c;其实在编…