Spring Boot日志:SLF4J和Logback

日志的分类

SpringBoot中的日志库分为两种:

  1. 实现库:提供具体的日志实现,例如日志级别的控制、打印格式、输出目标等。
  2. 外观库:自身不提供日志实现,而是对其他日志库进行封装,从而方便使用。基于外观模式实现。

关于外观库的出现,可设想一下:现在有多种日志库,每一种接口都不同。于是我们在不同项目中往往需要调用不同的API。于是希望,无论哪一种日志库,我们都在外面套一层壳,使用时调用这层壳的接口,这样就统一了。这层壳就是外观库。

对于这两种库,常见的有:

  1. 实现库:Log4jLog4j2Logback
  2. 外观库:Slf4jApache Commons Logging

通常只需要引入Slf4j依赖,然后通过Slf4j来调用LogbackLog4j

对应地,配置文件除了对Slf4j进行配置,也可以对LogbackLog4j进行配置。

Logback相比于Log4j,性能提高了10倍以上的性能,占用的内存也变小了,并且文档十分详细。推荐使用Slf4j+Logback

官网:

https://logback.qos.ch/

官方文档:

https://logback.qos.ch/documentation.html

Slf4jLogbackLog4j是同一个作者,使用了相同的设计,因此Slf4j直接可调用LogbackLog4j。而对于其他日志实现库,例如java.util.logging等,需要使用一个适配器模块来将Apache Commons Logging的接口转换为Slf4j的可调用接口。

Spring Boot日志

依赖

Spring Boot默认使用Logback。只需要引入spring-boot-starterspring-boot-starter-web就会默认包含,不需要再单独引入。
lombok中默认包含了Slf4j,因此只要引入了lombok就无需再单独引入Slf4j

xml 复制代码
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.24</version>
</dependency>

日志对象

要打印,就要先获取日志对象。

通常地,使用Slf4j包中的LoggerFactory来得到日志对象,然后打印:

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LoggerController {
    // 得到日志对象
    private Logger logger = LoggerFactory.getLogger(LoggerController.class);
    @RequestMapping("/logger")
    public String logger() {
        // 日志打印
        logger.trace("日志级别: trace");
        logger.debug("日志级别: debug");
        logger.info("日志级别: info");
        logger.warn("日志级别: warn");
        logger.error("日志级别: error");
        return "logger";
    }
}

如果项目中引入了lombok组件,则可在类前添加@Slf4j注解,这样就可在类中直接使用log日志对象,而无需通过LoggerFactory来获取。

复制代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j // 通过lombok的`@Slf4j`得到日志实例
public class LoggerController {
    @RequestMapping("/logger")
    public String logger() {
        // 日志打印
        log.trace("日志级别: trace");
        log.debug("日志级别: debug");
        log.info("日志级别: info");
        log.warn("日志级别: warn");
        log.error("日志级别: error");
        return "logger";
    }
}

日志级别及配置

日志级别

日志有8个级别:

  1. ALL: 开启所有日志
  2. TRACE: 追踪,程序每次执行一步都输出。级别较低,通常不会使用
  3. DEBUG: 调试日志,细粒度
  4. INFO: 普通日志,粗粒度
  5. WARN: 警告日志
  6. ERROR: 错误日志,但不影响系统同运行
  7. FATAL: 严重错误日志,会导致系统退出
  8. OFF: 关闭所有日志

对于这8个级别,级别依次递增。级别越高,打印的日志越少。

通常地,只使用TRACEDEBUGINFOWARNERROR这5个等级。

Spring Boot会打印指定级别及更高级的日志。

例如日志设置为INFO级,那么Spring Boot会打印INFOWARNERROR

配置文件

logback的配置可在application.yml和xml中配置,其中xml配置更加灵活。

若多个配置同时存在,则其加载顺序为:

logback.xml → application.yml → logback-spring.xml

后加载的会覆盖先加载的。因此application.yml 会覆盖logback.xml 中的相同配置。即后加载的优先级更高。

同理,若要使用 application.yml 中定义的变量,应使用 logback-spring.xml 。官方推荐使用 logback-spring.xml

logback.xml

加载logback.xml 时,默认会在classpath查找以下文件: 用户自定义xml > logback-test.xml > logback.groovy > logback.xml 。

如果上述4个配置文件都不存在,那么logback会调用BasicConfigurator来创建一个最小化配置将日志输出到控制台。最小化配置会构造一个父为<ROOT><ConsoleAppender>PatternLayoutEncoder%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n

其中用户自定义xml是在application.yml 中通过logging.config=classpath:logging-config.xml配置的。

yml配置

yml 复制代码
logging:
  config: classpath:logback.xml # 自定义配置文件
  pattern:
    file: "%d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{15} - %msg %n)"     # 文件输出
    console: "%d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{15} - %msg %n)"  # 控制台输出
  file:
    name: E:\logs\test.log # 日志文件输出路径
  level:
    root: INFO # root输出级别
    com.spring: WARN # 特定包的输出级别

xml结构

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    </appender>

    <appender name="ROLLING" class="ch.qos.logback.core.RollingFileAppender">
    </appender>

    <root></root>
    <logger></logger>
</configuration>

注意区分属性配置的区别:

  • 属性:标签自身的属性,直接写在标签标签内,例如<appender name ="CONSOLE">,name就是`标签的属性。
  • 配置:标签的功能设置,使用子标签进行配置,例如<appender><file>testFile.log</file></appender><file>就是<appender>标签的配置。

最外层标签<configuration>

<configuration>是最外层的标签,所有其他标签都要定义在该标签内。
<configuration>可设置多个属性:

  • scan: 启用扫描。默认为true。当为true时,若配置文件发生变更,将会被重新加载。
  • scanPeriod: 配置文件扫描时间间隔。默认单位是毫秒,可修改。当scan为true时,此属性生效。默认时间间隔为1分钟。
  • debug: 默认为false。若设为true,将实时打印出logback内部日志信息。

例如:

xml 复制代码
<configuration scan="false" scanPeriod="60 seconds" debug="false">

<contextName>上下文名称

为了避免同一服务器上多个web应用的logger产生上下文冲突,可使用<contextName>标签设置上下文的名称,确保每个xml的<contextName>唯一即可。

例如:

xml 复制代码
<contextName>Test</contextName>

<appender>标签

<appender>标签负责写日志。定义了日志的输出位置、触发策略、格式等。注意只负责写,不负责日志等级。

一个<appender>标签负责一种日志。由于一个系统中往往包含多种日志,因此通常同时使用多个<appender>标签。
<appender>包含2个属性:

  • name: 指定<appender>的名称,可自定义。需在root标签中引用。
  • class: 指定所使用实现库中Appender类的含路径名称。

关于class,有以下几个常用取值:

  • ch.qos.logback.core.ConsoleAppender: 输出到控制台。
  • ch.qos.logback.core.FileAppender: 输出到静态记录文件。
  • ch.qos.logback.core.rolling.RollingFileAppender: 输出到滚动日志文件。

ConsoleAppender

ConsoleAppender最为简单,直接输出到控制台。通常用于开发调试。
ConsoleAppender常用的设置为:

  • <encoder>: 对记录事件进行格式化。

例如:

xml 复制代码
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>console %d %p - %m%n</pattern>
    </encoder>
</appender>

FileAppender

FileAppender会将所有的日志信息都写入到一个文件中。因此若append属性为true,则日志文件会越来越大。
FileAppender常用的设置为:

  • <file>: 文件名。无默认值,必须设置。其路径可以为绝对或相对。若上级目录不存在则会自动创建。
  • <append>: 是否开启追加。默认为true。若为true,则新的日志会追加到文件末尾;若为false,则写新日志前会清空日志文件。
  • <encoder>: 对记录事件进行格式化。
  • <prudent>: 是否安全写入文件。默认为false。效率低。

例如:

xml 复制代码
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
  <file>testFile.log</file>
  <append>true</append>
  <encoder>
     <pattern>%d %p - %m%n</pattern>
  </encoder>
</appender

RollingFileAppender

RollingFileAppender会将日志滚动记录,即写入一个文件,当满足条件时,再写入下一个文件。例如设置文件大小为30MB,则当写入的日志文件达到30MB时会再新建一个日志文件进行写入。达到条件 这个行为称为滚动。
RollingFileAppender常用的设置为:

  • <file>: 文件名。无默认值,必须设置。其路径可以为绝对或相对。若上级目录不存在则会自动创建。
  • <append>: 是否开启追加。默认为true。若为true,则新的日志会追加到文件末尾;若为false,则写新日志前会清空日志文件。
  • <rollingPolicy>: 滚动策略。通常包含:滚动条件(例如最大日志文件大小),文件命名格式,日志文件保存期限,等等。
  • <layout>: 日志输出格式。

例如:

xml 复制代码
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>testFile.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>${LOG_HOME}/${app-name}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
        <MaxHistory>30</MaxHistory>
        <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>30MB</maxFileSize>
        </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
	<!-- 日志输出格式: -->
    <layout class="ch.qos.logback.classic.PatternLayout">
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %-5level ] [ %thread ] -  [ %logger{50} : %line ] - %msg%n</pattern>
    </layout>
</appender

<rollingPolicy>滚动策略

<rollingPolicy>使用class属性指定滚动策略,不同的策略有不同的配置。

  1. 基于时间的滚动策略:ch.qos.logback.core.rolling.TimeBasedRollingPolicy
    该策略根据时间来判定是否触发滚动。最常用。
    常用配置为:
  • <fileNamePattern>: 文件名格式,必须。可以使用%d转换符来接收一个java.text.SimpleDateFormat对象,例如%d{yyyy-MM-dd HH:mm:ss.SSS}
  • <maxHistory>: 日志文件保留天数。
  1. 基于文件大小的滚动策略:ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy
    该策略会监视日志文件大小,当文件超过指定大小时触发滚动。
  • <maxFileSize>: 日志文件大小,默认为10MB。
  • <prudent>: 是否安全写入文件。若为true,不支持FixedWindowRollingPolicy。支持TimeBasedRollingPolicy,但此时必须满足:1不支持也不允许文件压缩;2不能设置file属性。
  • <triggeringPolicy>: 告知 RollingFileAppender 何时激活滚动。

<root>标签

<root>标签有2个作用:

  1. 定义日志的输出等级。
  2. 指定哪些<appender>启用。

<root>name属性固定为ROOT,且没有上级,故而<root>只有一个属性:

  • level: 最重要 ,指定日志的打印等级,默认为DEBUG。其值可以为:ALLTRACEDEBUGINFOWARNERROR,FATALOFF。不可以设置为INHERITEDNULL`。

可以在<root>下配置多个<appender-ref>,标识对应的<appender>被添加到<root>下,从而可以继承<root>的属性和内容。

例如:

xml 复制代码
<root level="INFO">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE" />
    <appender-ref ref="ROLLING" />
</root>

其中<appender-ref>ref属性即为<appender><logger>name属性。
<root>也是一个特殊的<logger>,且为所有<logger>的最上级父。<root>parent属性为null

<logger>标签

<logger>标签非必须,用于对某些日志等级进行单独定义。

例如设置<root level="INFO">,但希望springframework的等级为WARN,此时就可添加一个<logger>标签:

复制代码
<logger name="org.springframework" level="WARN"/>

<logger>常用属性为:

  • name: 指定需单独设置的组件类名。
  • level: 设置组件的日志等级。其值可以为:ALLTRACEDEBUGINFOWARNERROR,FATALOFF。可设置为INHERITEDNULL`。若不设置,则默认继承上级的level。
  • additivity: 是否向上级<logger>传递打印信息。默认为true。若为true,则本<logger>打印一次,然后传递给上级<logger>,上级<logger>会再打印一次,这样就会造成重复打印。因此通常都设置为false

例如:

xml 复制代码
<logger name="TEST_PARENT" level="INFO" additivity="false">
    <appender-ref ref="TEST_CHILD"/>
</logger>

这样就形成了父子关系,TEST_CHILD的上级为TEST_PARENT
<logger>有一个parent属性,指向其父<logger>。每个<logger>都有parent,只有<root>除外,<root>是根节点。因此<root>和所有的<logger>会形成一棵树。注意父子关系是由parent属性形成的,而非类继承这样的关系。

定义变量

变量有两种:本地变量和配置文件变量。

本地变量<property>

在xml中定义一个变量,然后在整个xml文件中引用。格式为:

xml 复制代码
<property name="变量名" value="变量值" />  

通过${变量名}格式使用变量。例如:

xml 复制代码
<!-- 定义变量 -->
<property name="LOG_HOME" value="E:/logs/" />

<!-- 使用变量 -->
<appender>
	<file>${LOG_HOME}/${app-name}.log</file>
</appender>

配置文件变量<springProperty>

若希望从yml或.properties中读取变量值在xml中使用,则需要使用<springProperty>

例如,在application.yml 中定义了一个logback_app_property.level变量:

yml 复制代码
logback_app_property:
  level: INFO

现在希望引用这个level变量,则可在xml中添加<springProperty>标签,并令其source属性指向logback_app_property.level变量。

xml 复制代码
<springProperty name="YML_LEVEL" source="logback_app_property.level" defaultValue="INFO"/>

同样是通过${变量名}格式使用变量:

xml 复制代码
<root level="${YML_LEVEL}">
</root>

实例

首先在yml中定义

yml 复制代码
logging:
  # 指定 logback-app.xml 作为logback的配置文件
  config: classpath:logback-app.xml

# 用于 logback-app.xml 文件配置的参数值
logback_app_property:
  # TRACE < DEBUG < INFO < WARN < ERROR
  level: INFO

然后在logback-app.xml中定义:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <contextName>Application</contextName>

    <jmxConfigurator/>
	
    <!-- 定义日志的保存目录 -->
    <!-- <property name="LOG_HOME" value="/app/logs/" /> -->
    <property name="LOG_HOME" value="E:/logs/" />
    <property name="app-name" value="test-admin"/>
    <property name="filename" value="server"/>
	
    <!-- 编码设置 -->
    <property name="ENCODER_PATTERN" value="%red(%date{ISO8601}]) %highlight(%-5level) %green([%10.10thread]) [%X{X-B3-TraceId}] %boldMagenta(%logger{20}) - %cyan(%msg%n)" />

    <!-- 控制台输出 -->
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${ENCODER_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 滚动输出到文件:将日志记录到指定文件,满足条件时,再写入下一个文件 -->
    <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 指定日志文件的名称 -->
        <file>${LOG_HOME}/${app-name}.log</file>
        <!-- TimeBasedRollingPolicy: 基于时间的滚动策略,该策略根据时间来判定是否触发滚动。  -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--
            滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
            %i:当文件大小超过maxFileSize时,按照i进行文件滚动
            -->
            <fileNamePattern>${LOG_HOME}/${app-name}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
            <!--
            可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。
            假如设置每天滚动,maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。
            注意,删除旧文件时那些为了归档而创建的目录也会被删除。
            -->
            <MaxHistory>30</MaxHistory>
            <!--
            当日志文件超过maxFileSize指定的大小时,根据上面提到的%i进行日志文件滚动。
            注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
            -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>30MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <!-- 日志输出格式: -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %-5level ] [ %thread ] -  [ %logger{50} : %line ] - %msg%n</pattern>
        </layout>
    </appender>

    <!-- error信息输出 -->
    <appender name="errorLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/${app-name}-error.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/${app-name}-error-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>90</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %-5level ] [ %thread ] -  [ %logger{50} : %line ] - %msg%n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
        </filter>
    </appender>

    <!-- 这些日志不要打印debug,不然数量太多 -->
    <!-- 选择使用的框架进行配置 -->
    <logger name="org.springframework" level="WARN"/>
    <logger name="org.spring" level="WARN"/>
    <logger name="org.hibernate" level="WARN"/>
    <logger name="io.grpc.netty" level="OFF"/>
    <logger name="org.eclipse.jetty" level="WARN"/>
    <logger name="jndi" level="WARN"/>
    <logger name="redis.clients" level="WARN"/>
    <logger name="application" level="WARN"/>
    <logger name="springfox.documentation" level="WARN"/>
    <logger name="com.netflix" level="WARN"/>
    <logger name="org.reflections" level="WARN"/>
    <logger name="org.apache" level="WARN"/>
    <logger name="io.grpc.internal.ClientCallImpl" level="OFF"/>
    <logger name="org.springframework.amqp.rabbit" level="ERROR"/>
    <logger name="com.baomidou.dynamic.datasource.DynamicRoutingDataSource" level="WARN"/>
    <logger name="com.zaxxer.hikari.pool.HikariPool" level="WARN"/>
    <logger name="org.quartz.core.QuartzSchedulerThread" level="ERROR"/>
    <logger name="io.lettuce.core.protocol.RedisStateMachine" level="INFO"/>
    <logger name="io.lettuce.core.RedisChannelHandler" level="INFO"/>
    <logger name="io.lettuce.core.protocol.CommandHandler" level="INFO"/>
    <logger name="io.lettuce.core.protocol.CommandEncoder" level="INFO"/>
    <logger name="io.lettuce.core.protocol.DefaultEndpoint" level="INFO"/>
    <logger name="io.lettuce.core.protocol.ConnectionWatchdog" level="INFO"/>
    <logger name="io.lettuce.core.RedisClient" level="INFO"/>
    <logger name="org.mybatis.spring.mapper.ClassPathMapperScanner" level="INFO"/>
    <logger name="com.baomidou.mybatisplus.core.MybatisConfiguration" level="INFO"/>

    <!-- 配置文件变量 -->
    <springProperty name="LEVEL" source="logback_app_property.level" defaultValue="INFO"/>

    <root level="${LEVEL}">
        <appender-ref ref="consoleAppender"/>
        <appender-ref ref="appLogAppender" />
        <appender-ref ref="errorLogAppender" />
    </root>
</configuration>

在程序中动态更改日志级别

在程序中使用代码来动态修改日志级别,首先导入库:

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;

然后获取<ROOT>并修改level

java 复制代码
String loggerName = "ROOT";
String loggerLevel = "DEBUG";
// 获取日志上下文
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
// 获取ROOT
ch.qos.logback.classic.Logger logger = loggerContext.getLogger(loggerName);
// 修改日志等级
logger.setLevel(Level.valueOf(loggerLevel));

注意这里的loggerName与JMX不同,是大小写不敏感的,例如ROOT可以写作root

Java管理扩展 JMX(Java Management Extensions)

JMX是一个带窗口的应用程序,为运行中的应用提供管理功能。JMX是跨平台的,与具体应用无关。配置logback开启JMX后即可通过JMX查看logback信息。

配置logback开启JMX,需在xml中添加一行标签:

复制代码
<configuration>
  <jmxConfigurator />
</configuration>

当应用运行后,打开系统的CMD窗口,在其中输入命令:

jconsole

然后就会打开JMX的应用窗口,并提示新建连接 。设应用程序运行在本地,则在本地进程的列表中选择对应的应用程序,然后双击或点连接

之后可能弹出安全连接失败。是否以不安全的方式重试? ,选择不安全的连接即可。

在上方的标签列表中点击MBean 标签,然后在列表中找到ch.qos.logbak.classic,依次点击进入defaultch.qos.logback.classic.jmx.JMXConfigurator,其下会列出属性操作两个列表。在其下分别包含不同的功能。

对于属性,包含LoggerListStatuses。其中LoggerList列出了所有的Logger。特殊地,<root>标签其对应名称为ROOT,会列在第一行。

对于操作,可进行:

  • 重新加载logback的默认配置文件。
  • 通过指定的URL重新加载配置文件。
  • 通过指定的文件重新加载配置文件。
  • 设置指定logger级别,可设为null
  • 获取指定logger级别,可返回null
  • 指定logger的有效级别。

点击属性 下的LoggerList,即可看到一个Logger数组。第一个就是ROOT

点击操作 下的getLoggerLevel,需输入一个参数p1,该参数就是LoggerList中的一个Logger。输入ROOT,然后点击按钮getLoggerLevel ,即可看到ROOT的等级。注意这里的p1是大小写敏感的,例如ROOT不可以写作root

点击操作 下的setLoggerLevel,需输入两个参数p1p2p1为Logger名称,p2为level值。例如p1输入ROOTp2输入DEBUG,然后点击按钮setLoggerLevel ,即可将ROOT变更为DEBUG等级。

同理,更改应用的配置文件 logback.xml ,然后点击 操作 下的reloadDefaultConfiguration,并点击右侧的reloadDefaultConfiguration按钮,即可重新加载配置文件。

但在实际测试中,若配置文件为 logback.xml ,则表现相对正常;而若配置文件为其他名称,例如 logback-spring.xml ,则重载配置文件后原控制台将不再进行打印,且对配置文件的修改也不会生效。似乎reloadDefaultConfiguration只识别 logback.xml

另外,修改配置文件只能是更改 logback.xml 本身。如果修改的是application.yml 中的logback_app_property.level变量,reloadDefaultConfiguration时并不会重新读取该变量并应用到 logback.xml 中。

一般来说,通过JMX来修改的只有ROOT,以及logback.xml 中配置的多个<logger>

相关推荐
sniper_fandc1 小时前
SpringBoot系列—入门
java·spring boot·后端
Albert Edison7 小时前
【最新版】IntelliJ IDEA 2025 创建 SpringBoot 项目
java·spring boot·intellij-idea
Piper蛋窝8 小时前
深入 Go 语言垃圾回收:从原理到内建类型 Slice、Map 的陷阱以及为何需要 strings.Builder
后端·go
六毛的毛10 小时前
Springboot开发常见注解一览
java·spring boot·后端
AntBlack10 小时前
拖了五个月 ,不当韭菜体验版算是正式发布了
前端·后端·python
315356691310 小时前
一个简单的脚本,让pdf开启夜间模式
前端·后端
uzong11 小时前
curl案例讲解
后端
开开心心就好11 小时前
免费PDF处理软件,支持多种操作
运维·服务器·前端·spring boot·智能手机·pdf·电脑
一只叫煤球的猫12 小时前
真实事故复盘:Redis分布式锁居然失效了?公司十年老程序员踩的坑
java·redis·后端
猴哥源码12 小时前
基于Java+SpringBoot的农事管理系统
java·spring boot