Spring Boot日志:SLF4J和Logback

news2025/1/8 14:04:18

日志的分类

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

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.24</version>
</dependency>

日志对象

要打印,就要先获取日志对象。
通常地,使用Slf4j包中的LoggerFactory来得到日志对象,然后打印:

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配置

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 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内部日志信息。

例如:

<configuration scan="false" scanPeriod="60 seconds" debug="false">

<contextName>上下文名称

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

<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>: 对记录事件进行格式化。

例如:

<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。效率低。

例如:

<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>: 日志输出格式。

例如:

<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>的属性和内容。
例如:

<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

例如:

<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文件中引用。格式为:

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

<!-- 定义变量 -->
<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变量:

logback_app_property:
  level: INFO

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

<springProperty name="YML_LEVEL" source="logback_app_property.level" defaultValue="INFO"/>

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

<root level="${YML_LEVEL}">
</root>

实例

首先在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 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>

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

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;

然后获取<ROOT>并修改level

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>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

接口自动化测试-Python+Requests+Pytest+YAML+Allure配套撸码(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 接口自动化框架&a…

软件测试/测试开发丨Pytest测试框架学习笔记

Pytest 参数化用例 测试登录场景 测试登录成功&#xff0c;登录失败(账号错误&#xff0c;密码错误)*创建多种账号: 中⽂文账号&#xff0c;英⽂文账号*普通测试用例方法Copy 多份代码 or 读⼊入参数?*一次性执⾏多个输⼊入参数* def test_param_login_ok():# 登录成功user…

解决分类任务中数据倾斜问题

大家好&#xff0c;在处理文本分类任务时&#xff0c;基准测试流行的自然语言处理架构的性能是建立对可用选项的理解的重要步骤。在这里&#xff0c;本文将深入探讨与分类相关的最常见的挑战之一——数据倾斜。如果你曾经将机器学习&#xff08;ML&#xff09;应用于真实世界的…

selenium---滑动框验证码破解

前言 目前常见的验证码有很多种&#xff0c;比如数字验证码&#xff0c;滑动验证码&#xff0c;以及滑动补全图像验证码等&#xff0c;关于验证码的操作属于我们在UI自动化很大的一个障碍&#xff0c;今天安静来介绍下如何通过python来实现我们滑动验证码 滑动验证码 先来一…

MySQL之全文索引二三事

全文索引 MySQL全文索引是一种用于快速搜索文本字符串的索引&#xff0c;在MySQL数据库中&#xff0c;它可以用来提高文本搜索的效率。全文索引不同于普通索引&#xff0c;普通索引只是对列值进行排序&#xff0c;而全文索引则会对列的内容进行分词&#xff0c;并且对每个分词…

RocketMQ重复消费的解决方案::分布式锁直击面试!

文章目录 场景分析方法的幂等分布式锁Redis实现分布式锁抢锁的设计思路 分布式锁案例 直击面试rocketmq什么时候重复消费消息丢失的问题消息在哪里丢失发送端确保发送成功并且配合失败的业务处理消费端确保消息不丢失rocketmq 主从同步刷盘 场景分析 分布式系统架构中,队列是分…

go-zero学习 第六章 分布式事务dtm

go-zero学习 第六章 分布式事务dtm 1 参考文档2 官方示例3 go-zero使用dtm参考代码3.1 go-zero支持dtm 代码操作步骤※3.2 gozerodtm 代码操作步骤 4 注意事项4.1 grpc接口地址※4.2 动态调用过程4.3 dtm的回滚补偿4.4 barrier的空补偿、悬挂等4.5 barrier在rpc中本地事务 1 参…

多媒体工作中用到的小工具

安利下嵌入式多媒体用到的各种小工具 下面是同事们推荐的 以下是对这些软件的简要介绍: ocenaudio:ocenaudio是一款跨平台的音频编辑软件,它提供了直观的界面和丰富的功能,可以帮助用户进行音频剪辑、修复、转码等操作。 MKVToolNix:MKVToolNix是一款开源的多媒体容器格…

web-vim信息泄露

&#xff08;1&#xff09;知识补充 vim 交换文件名 在使用vim时会创建临时缓存文件&#xff0c;关闭vim时缓存文件则会被删除&#xff0c;当vim异常退出后&#xff0c;因为未处理缓存文件&#xff0c;导致可以通过缓存文件恢复原始文件内容   以 index.php 为例&#xff1…

Redis一主二从三哨兵模式

文章目录 Redis一主二从三哨兵模式环境配置实践配置主从配置哨兵模式 测试主从复制测试模拟master宕机恢复master Redis一主二从三哨兵模式 当你使用Redis作为主从复制的架构&#xff0c;并且希望在出现主节点故障时自动进行故障转移时&#xff0c;适用于一主而从三哨兵模式。…

android 面试题目之handler消息机制

Handler消息机制是Android里面很基础的东西&#xff0c;基本上属于必考题 一般会从如下几个方面来考查 实现原理&#xff0c;Handler/Message/MessageQueue/Looper 几个类的实现流程&#xff0c;Handler导致的内存泄露怎么处理主线程的Looper是什么时候创建的&#xff1b;如果…

3. Spring 更简单的读取和存储对象(五大类注解 方法注解)

目录 1. 存储 Bean 对象 1.1 配置扫描路径 1.2 添加注解存储 Bean 对象 1.2.1 Controller&#xff08;控制器存储&#xff09; 1.2.2 Service&#xff08;服务存储&#xff09; 1.2.3 Repository&#xff08;仓库存储&#xff09; 1.2.4 Component&#xff08;组件存储&…

C语言学习笔记 Ubuntu系统下部署gcc编译工具-01

在22.04版本 ubuntu系统下&#xff1a; 1.进行apt工具包更新 sudo apt-get update 2.安装gcc工具 sudo apt-get install -y gcc 3.创建一下文件&#xff0c;并编译它输出相应的内容 touch hello.c 4.使用gcc编译c源程序并运行 格式&#xff1a;gcc 源文件名 -o 生成的执行文…

AcWing 1210. 连号区间数

输入样例1&#xff1a; 4 3 2 4 1输出样例1&#xff1a; 7输入样例2&#xff1a; 5 3 4 2 5 1输出样例2&#xff1a; 9样例解释 第一个用例中&#xff0c;有 77 个连号区间分别是&#xff1a;[1,1],[1,2],[1,3],[1,4],[2,2],[3,3],[4,4][1,1],[1,2],[1,3],[1,4],[2,2],[3,3…

记一次vscode配置CMake编译task的坑

事情经过是这样的&#xff0c;博主在一个项目中需要使用交叉编译链进行项目编译&#xff0c;但是在CMake中有一个自定义的编译选项&#xff0c;在vscode中配置task任务后&#xff0c;编译发现终端报静态库.a文件格式错误&#xff0c;如下图所示&#xff1a; 但是如果在CMakeLis…

python与深度学习(七):CNN和fashion_mnist

目录 1. 说明2. fashion_mnist实战2.1 导入相关库2.2 加载数据2.3 数据预处理2.4 数据处理2.5 构建网络模型2.6 模型编译2.7 模型训练2.8 模型保存2.9 模型评价2.10 模型测试2.11 模型训练结果的可视化 3. fashion_mnist的CNN模型可视化结果图4. 完整代码 1. 说明 本篇文章是C…

Install the Chinese input method on Linux

Open terminal and input: sudo -i apt install fcitx fcitx-googlepinyinWait for it to finish. Search fcitx: "设置"-->"输入法": Finally, we get the following result&#xff1a; Ctrl Space&#xff1a;Switch the input method. The test …

Redis追本溯源(三)内核:线程模型、网络IO模型、过期策略与淘汰机制、持久化

文章目录 一、Redis线程模型演化1.Redis4.0之前2.Redis4.0之后单线程、多线程对比3.redis 6.0之后 二、Redis的网络IO模型1.基于事件驱动的Reactor模型2.什么是事件驱动&#xff0c;事件驱动的Reactor模型和Java中的AIO有什么区别3.异步非阻塞底层实现原理 三、Redis过期策略1.…

印刷和数字设计的页面布局软件 QuarkXPress 2023 Crack

QuarkXPress 2023 用于印刷 和数字设计的页面布局软件&#xff0c;使用 QuarkXPress 释放您的创造力并最大限度地提高生产力 图形设计和桌面出版流程早就应该进行创新和颠覆&#xff0c;所以 QuarkXPress 就来了。自 1987 年首次亮相市场以来&#xff0c;成千上万的创意专业人士…

RocketMQ教程-(5)-功能特性-事务消息

事务消息为 Apache RocketMQ 中的高级特性消息&#xff0c;本文为您介绍事务消息的应用场景、功能原理、使用限制、使用方法和使用建议。 事务消息为 Apache RocketMQ 中的高级特性消息&#xff0c;本文为您介绍事务消息的应用场景、功能原理、使用限制、使用方法和使用建议。…