日志框架的使用

news2024/9/19 7:52:53

一、日志概述

日志:用来记录程序运行过程中的信息,并可以进行永久存储。
  1. 开发过程中可能会出现以下需求:
  • 希望系统能记住某些数据是被谁操作的,比如被谁删除了?
  • 想分析用户浏览系统的具体情况,以便挖掘用户的具体喜好?
  • 当系统在开发或者上线后出现了bug,崩溃了,该通过什么去分析、定位bug?
  • 用来记录程序运行过程中的信息,并可以进行永久存储。好比生活中的日记,可以记录你生活的点点滴滴。
  1. 在开发过程中输出语句会有弊端存在:
  • 信息展示在控制台
  • 不能方便的将其记录到其他的位置(文件,数据库)
  • 想取消记录的信息需要修改代码才可以完成

  1. 日志技术应该具备哪些特点和优势
  • 可以将系统执行的信息,方便的记录到指定的位置(控制台、文件中数据库中)。
  • 可以随时以开关的形式控制是日志的记录和取消,无需侵入到源代码中去进行修改。

1.1 日志的种类

+ 日志文件

日志文件是用于记录系统操作事件的文件集合,可分为事件日志和消息日志。具有处理历史数据、诊断问题的追踪以及理解系统的活动等重要作用。

在计算机中,日志文件是记录在操作系统或其他软件运行中发生的事件或在通信软件的不同用户之间的消息的文件。记录是保持日志的行为。在最简单的情况下,消息被写入单个日志文件。

许多操作系统,软件框架和程序包括日志系统。广泛使用的日志记录标准是在因特网工程任务组(IETF)RFC5424中定义的syslog。 syslog标准使专用的标准化子系统能够生成,过滤,记录和分析日志消息。

  • 调试日志

软件开发中,我们经常需要去调试程序,做一些信息,状态的输出便于我们查询程序的运行状况。为了让我们能够更加灵活和方便的控制这些调试的信息,所有我们需要专业的日志技术。java中寻找bug会需要重现。调试也就是debug 可以在程序运行中暂停程序运行,可以查看程序在运行中的情况。日志主要是为了更方便的去重现问题。

  • 系统日志

系统日志是记录系统中硬件、软件和系统问题的信息,同时还可以监视系统中发生的事件。用户可以通过它来检查错误发生的原因,或者寻找受到攻击时攻击者留下的痕迹。系统日志包括系统日志、应用程序日志和安全日志。

系统日志策略可以在故障刚刚发生时就向你发送警告信息,系统日志帮助你在最短的时间内发现问题。

系统日志是一种非常关键的组件,因为系统日志可以让你充分了解自己的环境。这种系统日志信息对于决定故障的根本原因或者缩小系统攻击范围来说是非常关键的,因为系统日志可以让你了解故障或者袭击发生之前的所有事件。为虚拟化环境制定一套良好的系统日志策略也是至关重要的,因为系统日志需要和许多不同的外部组件进行关联。良好的系统日志可以防止你从错误的角度分析问题,避免浪费宝贵的排错时间。另外一种原因是借助于系统日志,管理员很有可能会发现一些之前从未意识到的问题,在几乎所有刚刚部署系统日志的环境当中。

1.2 日志级别

针对不同的场景,日志被分为五种不的级别,按照重要程度依次排序:
  • DEBUG 级别曰志记录对调试程序有帮助的信息。
  • INFO 级别日志 用来记录程序运行现场,虽然此处并未发生错误,但是对排查其他错误具有指导意义。
  • WARN 级别日志也可以用来记录程序运行现场,但是更偏向于表明此处有出现潜在错误的可能。
  • ERROR 级别日志表明当前程序运行发生了错误,需要被关注。但是当前发生的错误,没有影响系统的继续运行。
  • FATAL 级别曰志表明当前程序运行出现了严重的错误事件,并且将会导致应 用程序中断。

1.3 日志框架

日志框架分为三大部分:日志门面、日志适配器、日志库。利用门面设计模式将接口和实现解耦,使日志使用变得更加简单。

1.3.1 日志库(日志实现)

实现了日志的相关功能,主流的日志库有三个,分别是log4j、log-jdk、logback; 其中log4j和logback出自同一个作者,logback是log4j的升级版,且本身实现了slf4j日志门面接口;

log-jdk则是由JDK1.4之后提供的。由于这两种日志的实现不一样,所以用户使用时需要注意具体细节,这就衍生出了下面的日志门面。

  • 日志框架:大牛或者是第三方公司已经做好的实现代码,后来在可直接拿去使用。
    比如:Log4j

1.3.2 日志门面(Simple Logging Facade for Java)

日志门面只提供一套**接口规范**,他是对所有日志框架制定的**一种规范、标准、接口**,并不是一个框架的具体的实现,不负责日志功能的实现,目的是让使用者不需要关心底库具体是哪个日志库来负责日志打印和使用细节等。

接口用于定制规范,可以有多个实现,使用时是面向接口的(导入的包都是 slf4j 的包而不是具体某个日志框架中的包),即直接和接口交互,不直接使用实现,所以可以任意的更换实现而不用更改代码中的日志相关代码。

目前使用最广泛的日志门面有slf4j和common-logging。

门面设计模式是面向对象设计模式中的一种,日志框架就是采用这种模式(类似于JDBC)。

  • 日志接口:一些规范,提供给日志的实现框架设计的标准。
    比如:Commons Logging(jcl)、Simple Logging Facade for Java(slf4j)

PS:阿里巴巴Java开发手册中对于日志的要求:

1.3.3 日志适配器

门面适配器: 日志门面(slf4j)规范是后来才出现的,因此日志库是没有实现门面接口的,所以要想slf4j+log4j的模式就需一个日志门面适配器(slf4j-log4j12)来解决接口不兼容的问题。 日志库适配器: 一些老的项目中已经直接使用了日志库的API,但是由于打印日志的地方太多,难以改动,所以需要一个适配器来完成从旧日志库的API到门面日志(slf4j)API的路由,这样就可以在不改动原来代码的情况下使用日志门面(slf4j)来统一管理日志,并且也不影响后期日子库的切换。

1.3.4 Java 中比较常用的日志框架:

+ log4j(` Log for Java` ):Apache 的一个开源项目,七种日志级别:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE + logback:是一个很成熟的日志框架,其实 logBack 和 log4j 出自一个人之手,这个人就是 Ceki Gülcü。logback 比 log4j 大约快 10 倍、消耗更少的内存,迁移成本也很低,自动压缩日志、支持多样化配置、不需要重启就可以恢复 I/O 异常等优势 + ** log4j2** :作者认为,log4j2已经不仅仅是 log4j 的一个升级版本了,而是从头到尾被重写的,这可以认为这其实就是完全不同的两个框架

二、 slf4j+logback 模式

官方网站:[ https://logback.qos.ch/index.html](https://logback.qos.ch/index.html)

Logback 日志框架分为以下模块:

  • logback-core:该模块为其他两个模块提供基础代码。(必须有)
  • logback-classic: 完整实现了slf4j API的模块。(必须有)
  • logback-access:于Tomcat 和 Jetty等 Servlet容器集成,以提供Http访问日志功能(可选模块)

想要使用LogBack日志框架,至少需要在项目中整合下面三个模块:

  • slf4j-api:日志接口
  • logback-core:基础模块
  • logback-classic:功能模块,完整的实现了slf4j API

2.1 实现步骤

2.1.1 导入依赖

在 SpringBoot 中默认使用Logback,所以加入了spring-boot-starter-web依赖后,他会自动包含Logback相关依赖,无需额外添加!

如果不是SpringBoot 框架开发就需要导入相关依赖。

导入Logback框架到项目中,在项目下新建文件夹lib,导入Logback的jar包到该文件夹下,并将存放jar文件的lib文件夹添加到项目依赖库中去。

或者是Maven项目,直接通过Maven导入相关依赖:

<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->

<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.4.5</version>
  <scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-core -->
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-core</artifactId>
  <version>1.4.5</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>2.0.7</version>
</dependency>

2.1.2 loback.xml 配置文件

将Logback的核心配置文件** logback.xm** l直接拷贝到src目录下(必须是src下)。

如果文件命名为logback-spring.xml或者logback.xml则将该文件放在resource根目录下框架就可以自动识别。其他命名则需要显示的在application.properties文件中指定文件位置:<font style="color:rgb(51, 51, 51);">logging.config=classpath:log/logback-spring.xml</font>

配置文件命名:官方推荐命名为logback-spring.xml,因为以-spring结尾的配置文件可以使用springProfile标签,该标签可以使用环境变量。当然可以自定义其他名称。其他名称则需和上面一样在配置文件中配置文件路径。

#=================================================================
# log 日志
#=================================================================
logging:
  config: classpath:logback.xml

logback.xml 配置文件内容:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <springProperty scope="context" name="logName" source="logging.file.name" defaultValue="log.log" />
    <!--定义日志文件的存储地址-->
    <property name="LOG_HOME" value="${logName}" />
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
    <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n" />
 
    <!-- 控制台输出 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    <!-- 输出到日志文件 -->
    <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}.%d{yyyy-MM-dd}.%i</FileNamePattern>
            <MaxHistory>30</MaxHistory>
            <MaxFileSize>50MB</MaxFileSize>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>
 
    <!-- 自定义logger -->
    <logger name="com.dispart" level="debug" additivity="false">
        <appender-ref ref="console" />
    </logger>
    <!--sql语句执行输出-->
    <logger name="org.apache.ibatis" level="debug" additivity="false">
        <appender-ref ref="console" />
    </logger>
 
    <root level="info" additivity="false">
        <appender-ref ref="console" />
    </root>
</configuration>

ps: 其它 logback.xml 文件内容示例: 详细参数修改方法 网上学习即可:

  • ruoyi项目中的 logback.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 日志存放路径 --> <!-- Linux中需要创建对应的日志目录,否则项目启动不了,Linux权限不足问题 -->
	<property name="log.path" value="/www/wwwroot/RuoYi-vue/springBoot/logs" />
    <!-- 日志输出格式 -->
	<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />

	<!-- 控制台输出 -->
	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<pattern>${log.pattern}</pattern>
		</encoder>
	</appender>
	
	<!-- 系统日志输出 -->
	<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
	    <file>${log.path}/sys-info.log</file>
        <!-- 循环政策:基于时间创建日志文件 -->
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志文件名格式 -->
			<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
			<!-- 日志最大的历史 60天 -->
			<maxHistory>60</maxHistory>
		</rollingPolicy>
		<encoder>
			<pattern>${log.pattern}</pattern>
		</encoder>
		<filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 过滤的级别 -->
            <level>INFO</level>
            <!-- 匹配时的操作:接收(记录) -->
            <onMatch>ACCEPT</onMatch>
            <!-- 不匹配时的操作:拒绝(不记录) -->
            <onMismatch>DENY</onMismatch>
        </filter>
	</appender>
	
	<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
	    <file>${log.path}/sys-error.log</file>
        <!-- 循环政策:基于时间创建日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志文件名格式 -->
            <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
			<!-- 日志最大的历史 60天 -->
			<maxHistory>60</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 过滤的级别 -->
            <level>ERROR</level>
			<!-- 匹配时的操作:接收(记录) -->
            <onMatch>ACCEPT</onMatch>
			<!-- 不匹配时的操作:拒绝(不记录) -->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
	
	<!-- 用户访问日志输出  -->
    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<file>${log.path}/sys-user.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 按天回滚 daily -->
            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 日志最大的历史 60天 -->
            <maxHistory>60</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>
	
	<!-- 系统模块日志级别控制  -->
	<logger name="com.ruoyi" level="info" />
	<!-- Spring日志级别控制  -->
	<logger name="org.springframework" level="warn" />

	<root level="info">
		<appender-ref ref="console" />
	</root>
	
	<!--系统操作日志-->
    <root level="info">
        <appender-ref ref="file_info" />
        <appender-ref ref="file_error" />
    </root>
	
	<!--系统用户操作日志-->
    <logger name="sys-user" level="info">
        <appender-ref ref="sys-user"/>
    </logger>
</configuration> 
  • FlowAble项目中的 loback-spring.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" scanPeriod="10 seconds">
    <contextName>logback</contextName>
    <!-- 格式化输出:%date表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
    <!-- 定义日志存储的路径 -->
    <property name="FILE_PATH" value="log/FlowService-log.%d{yyyy-MM-dd}.%i.log" />
    <!-- 控制台输出日志 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 日志级别过滤INFO以下 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <!-- 按照上面配置的LOG_PATTERN来打印日志 -->
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    <!--每天生成一个日志文件,保存30天的日志文件。rollingFile用来切分文件的 -->
    <appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${FILE_PATH}</fileNamePattern>
            <!-- keep 15 days' worth of history -->
            <maxHistory>30</maxHistory>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 日志文件的最大大小 -->
                <maxFileSize>2MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!-- 超出删除老文件 -->
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    <!-- project default level -->
    <logger name="net.sh.rgface.serive" level="ERROR" />
    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="console" />
        <appender-ref ref="rollingFile" />
    </root>
</configuration>

2.1.3 创建日志对象

创建Logback框架提供的Logger日志对象,后续使用其方法记录系统的日志信息。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public static final Logger LOGGER = LoggerFactory.getLogger("类名")

通过调用日志对象 LOGGER 的方法记录日志信息。

2.2 Logback输出位置、格式设置

对Logback日志框架的控制,都是通过核心配置文件** logback.xml** 来实现的。

  • Logback日志输出位置、格式设置:
    • 通过logback.xml 中的标签可以设置输出位置。
    • 通常可以设置2个日志输出位置:一个是控制台、一个是系统文件中

输出到控制台的配置标志:

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">

输出到系统文件的配置标志:

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

2.3 Logback日志级别设置

如果系统上线后想关闭日志,或者只想记录一些错误的日志信息,怎么办?
  • 可以通过设置日志的输出级别来控制哪些日志信息输出或者不输出。

日志级别:

  • ALL 和 OFF分别是打开、及关闭全部日志信息。
  • 除此之外,日志级别还有: ALL< TRACE < DEBUG < INFO < WARN < ERROR < OFF; 默认级别是DEBUG,对应其方法
  • 作用:当在logback.xml文件中设置了某种日志级别后,系统将只输出当前级别,以及高于当前级别的日志。

具体在设置位置在 logback 配置文件中标签的level属性中设置指定系统的日志级别。

<root level="INFO">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE" />
</root>

三、slf4j+log4j2模式

** 日志门面:SLF4J **

日志实现:log4j2

log4j2 官网:https://logging.apache.org/log4j/2.x/manual/configuration.html

Spring Boot 默认使用 logback,但相比较而言,log4j2 在性能上面会更好。SpringBoot 高版本都不再支持 log4j,而是支持 log4j2。

3.1 log4j2框架实现步骤

3.1.1 引入日志框架相关依赖

由于Spring Boot 内置的日志框架是logback,**会导致和 log4j2 冲突**, 所以要先排除项目中logback的依赖。同时引入log4j2。

log4j2 日志框架,依赖引入Maven:

 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <exclusions>
        <!-- 排除掉Spring Boot 默认配置组件(logback)  -->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!--  Spring Boot 默认使用 log4j2 日志需要依赖  -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
  • 或者采用下面这种方式引入依赖
	<dependency>  
      <groupId>org.apache.logging.log4j</groupId>  
      <artifactId>log4j-api</artifactId>  
      <version>2.5</version>  
  </dependency>  
  <dependency>  
      <groupId>org.apache.logging.log4j</groupId>  
      <artifactId>log4j-core</artifactId>  
      <version>2.5</version>  
  </dependency>  

3.1.2 创建 log4j2.xml 配置文件

在项目的 resource 目录下增加 log4j2.xml 配置文件:

配置文件内容:

<?xml version="1.0" encoding="UTF-8"?>
<!--
    6个优先级从高到低依次为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。
    如果设置优先级为WARN,那么OFF、FATAL、ERROR、WARN 4个级别的log能正常输出
    设置为OFF 表示不记录log4j2本身的日志,
 -->
<!-- status:用来指定log4j本身的打印日志级别,monitorInterval:指定log4j自动重新配置的监测间隔时间 -->
<Configuration status="fatal">
  <Properties>
    <Property name="baseDir" value="${sys:user.home}/logs/Gangbb-Springboot-Log"/>
  </Properties>

  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
      <ThresholdFilter level="info" onMatch="ACCEPT"
        onMismatch="DENY"/>
      <PatternLayout
        pattern="[%d{MM:dd HH:mm:ss.SSS}] [%level] [%logger{36}] - %msg%n"/>
    </Console>

    <!--debug级别日志文件输出-->
    <RollingFile name="debug_appender" fileName="${baseDir}/debug.log"
      filePattern="${baseDir}/debug_%i.log.%d{yyyy-MM-dd}">
      <!-- 过滤器 -->
      <Filters>
        <!-- 限制日志级别在debug及以上在info以下 -->
        <ThresholdFilter level="debug"/>
        <ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL"/>
      </Filters>
      <!-- 日志格式 -->
      <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
      <!-- 策略 -->
      <Policies>
        <!-- 每隔一天转存 -->
        <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
        <!-- 文件大小 -->
        <SizeBasedTriggeringPolicy size="100 MB"/>
      </Policies>
      <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
      <DefaultRolloverStrategy max="15"/>
    </RollingFile>

    <!-- info级别日志文件输出 -->
    <RollingFile name="info_appender" fileName="${baseDir}/info.log"
      filePattern="${baseDir}/info_%i.log.%d{yyyy-MM-dd}">
      <!-- 过滤器 -->
      <Filters>
        <!-- 限制日志级别在info及以上在error以下 -->
        <ThresholdFilter level="info"/>
        <ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
      </Filters>
      <!-- 日志格式 -->
      <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
      <!-- 策略 -->
      <Policies>
        <!-- 每隔一天转存 -->
        <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
        <!-- 文件大小 -->
        <SizeBasedTriggeringPolicy size="100 MB"/>
      </Policies>
      <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
      <DefaultRolloverStrategy max="15"/>
    </RollingFile>

    <!-- error级别日志文件输出 -->
    <RollingFile name="error_appender" fileName="${baseDir}/error.log"
      filePattern="${baseDir}/error_%i.log.%d{yyyy-MM-dd}">
      <!-- 过滤器 -->
      <Filters>
        <!-- 限制日志级别在error及以上 -->
        <ThresholdFilter level="error"/>
      </Filters>
      <!-- 日志格式 -->
      <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
      <Policies>
        <!-- 每隔一天转存 -->
        <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
        <!-- 文件大小 -->
        <SizeBasedTriggeringPolicy size="100 MB"/>
      </Policies>
      <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
      <DefaultRolloverStrategy max="15"/>
    </RollingFile>
  </Appenders>
  <!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。-->
  <!--然后定义loggers,只有定义了logger并引入的appender,appender才会生效-->
  <Loggers>
    <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
    <logger name="org.mybatis" level="info" additivity="false">
      <AppenderRef ref="Console"/>
    </logger>
    <!--监控系统信息-->
    <!--若是additivity设为false,则 子Logger 只会在自己的appender里输出,而不会在 父Logger 的appender里输出。-->
    <Logger name="org.springframework" level="info" additivity="false">
      <AppenderRef ref="Console"/>
    </Logger>

    <Root level="debug">
      <AppenderRef ref="Console"/>
      <AppenderRef ref="debug_appender"/>
      <AppenderRef ref="info_appender"/>
      <AppenderRef ref="error_appender"/>
    </Root>

  </Loggers>
</Configuration>

PS:其它log4j(2)-spring.xml 配置文件示例: u8项目中的日志框架配置文件

  • u8Cloud项目中的 log4j2.xml 配置文件示例:
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
	<appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<!--只接受程序中INFO级别的日志进行处理 -->
			<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" />
			<PatternLayout pattern="[%d{HH:mm:ss.SSS}] %-5level %class{36} %L %M - %msg%xEx%n" />
		</Console>
 
        <!--处理DEBUG级别的日志,并把该日志放到logs/debug.log文件中-->
        <!--打印出DEBUG级别日志,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileDebug" fileName="./logs/debug.log"
                     filePattern="logs/$${date:yyyy-MM}/debug-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <ThresholdFilter level="DEBUG"/>
                <ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout
                    pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="500 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
 
        <!--处理INFO级别的日志,并把该日志放到logs/info.log文件中-->
        <RollingFile name="RollingFileInfo" fileName="./logs/info.log"
                     filePattern="logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <!--只接受INFO级别的日志,其余的全部拒绝处理-->
                <ThresholdFilter level="INFO"/>
                <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout
                    pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="500 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
 
        <!--处理WARN级别的日志,并把该日志放到logs/warn.log文件中-->
        <RollingFile name="RollingFileWarn" fileName="./logs/warn.log"
                     filePattern="logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <ThresholdFilter level="WARN"/>
                <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout
                    pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="500 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
 
        <!--处理error级别的日志,并把该日志放到logs/error.log文件中-->
        <RollingFile name="RollingFileError" fileName="./logs/error.log"
                     filePattern="logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz">
            <ThresholdFilter level="ERROR"/>
            <PatternLayout
                    pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="500 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
 
        <!--druid的日志记录追加器-->
        <RollingFile name="druidSqlRollingFile" fileName="./logs/druid-sql.log"
                     filePattern="logs/$${date:yyyy-MM}/api-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %L %M - %msg%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="500 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
    </appenders>
 
    <loggers>
        <root level="INFO">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileWarn"/>
            <appender-ref ref="RollingFileError"/>
            <appender-ref ref="RollingFileDebug"/>
        </root>
 
        <!--记录druid-sql的记录-->
        <logger name="druid.sql.Statement" level="DEBUG" additivity="true">
            <appender-ref ref="druidSqlRollingFile"/>
        </logger>
 
        <!--log4j2 自带过滤日志-->
        <Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
        <Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
        <Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
        <logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
        <Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
        <Logger name="org.crsh.plugin" level="warn" />
        <logger name="org.crsh.ssh" level="warn"/>
        <Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
        <Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
        <logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="warn"/>
        <logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
        <logger name="org.thymeleaf" level="warn"/>
    </loggers>
</configuration>

3.2 log4j2配置文件解析

3.2.1 根节点 configuration 标签

有两个属性:status,monitorinterval;
- **<font style="color:rgb(51, 51, 51);">tatus</font>**<font style="color:rgb(51, 51, 51);">,用来指定log4j本身的打印日志级别  OFF>FATAL>ERROR>WARN>INFO>DEBUG>TRACE>ALL</font>
- **<font style="color:rgb(51, 51, 51);">monitorinterval </font>**<font style="color:rgb(51, 51, 51);">重新读取配置文件的监测间隔时间,单位是s,最小是5s.</font>

两个子节点:AppendersLoggers表名可以定义多个Appender和Logger;

  • Properties 标签(可选择)

用来定义常量属性(例如日志打印的模版),之后在其他配置项中通过${变量名}引用

3.2.2 Appenders 标签

常见的有三种子节点:** Console、RollingFile**
  • Console 标签

用来定义输出到控制台的Appender;

两个属性:name、target,

一个节点:PatternLayout

- name属性:<font style="color:rgb(51, 51, 51);">指定Appender的名字</font>
- <font style="color:rgb(51, 51, 51);">target属性:SYSTEM_OUT 或 SYSTEM_ERR,一般只设置默认:SYSTEM_OUT.</font>
- <font style="color:rgb(77, 77, 77);">PatternLayout 节点: </font><font style="color:rgb(51, 51, 51);">指定输出日志的格式,可以使用pattern属性与Properties中定义的日志打印模板常量相结合,控制日志输出的模版,不设置则默认为:%m%n</font>

  • RollingFile

用于将日志写入到指定的文件,可以指定当文件达到一定大小(如20MB)时,另起一个文件继续写入日志,另起一个文件就涉及到新文件的名字命名规则,因此需要配置文件命名规则!

- name 属性:指定 Appender的名称。
- fileName 属性:<font style="color:rgb(51, 51, 51);">指定输出日志的目的文件带全路径的文件名</font>
- **<font style="color:rgb(51, 51, 51);">filePattern 属性</font>**<font style="color:rgb(51, 51, 51);">:指定新建日志文件的名称格式</font>

- PatternLayout 节点:指定日志<font style="color:rgb(51, 51, 51);">输出格式,不设置默认为:%m%n</font>
- Policies <font style="color:rgb(51, 51, 51);">节点:  指定滚动</font>**<font style="color:rgb(51, 51, 51);">日志的策略</font>**<font style="color:rgb(51, 51, 51);">,就是什么时候进行新建日志文件输出日志</font>
    * **<font style="color:rgb(51, 51, 51);">TimeBasedTriggeringPolicy </font>**<font style="color:rgb(51, 51, 51);">节点: Policies 节点的子节点,基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour。modulate=true用来调整时间。</font>
    * **<font style="color:rgb(51, 51, 51);">SizeBasedTriggeringPolicy </font>**<font style="color:rgb(51, 51, 51);">节点:Policies子节点,基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小。</font>
    * **<font style="color:rgb(51, 51, 51);">DefaultRolloverStrategy </font>**<font style="color:rgb(51, 51, 51);">节点:用来指定同一个文件夹下最多有几个日志文件时开始删除最l旧的,创建新的(通过max属性);可以指定压缩级别(通过compressionLevel属性),compressionLevel的值通常是一个介于0到9之间的整数,其中:0表示无压缩,1表示最快的压缩速度(但压缩率最低),9表示最高的压缩率(但压缩速度最慢)</font>

3.3 日志参数模板

> 格式化输出: > > %date{yyyy-MM-dd HH:mm:ss.SSS}: 简写为%d 日期 2023-08-12 15:04:30,123 > > %thread: %t 线程名, main > > %-5level:%p 日志级别,从左往右至少显示5个字符宽度,不足补空格 INFO > > %msg:%m 日志消息 info msg > > %n: 换行符 > > {cyan}: 蓝绿色(青色) > > %logger{36}: %c 表示 Logger 名字最长36个字符 > > %highlight:高亮显示,%highlight{%-5level} > > %C: 类路径 com.qq.demolog4j2.TestLog4j2 > > %F: 类名 TestLog4j2.java > > %M: 方法名 main > > %L: 行号 12 > > %l: 日志位置, 相当于 %C.%M(%F.%L) com.qq.demolog4j2.TestLog4j2.main(TestLog4j2.java:16) >

log4j2.xml 配置文件示例内容:

<?xml version="1.0" encoding="UTF-8"?>
<!--
    6个优先级从高到低依次为:OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL
    如果设置优先级为WARN,那么OFF、FATAL、ERROR、WARN 4个级别的log能正常输出
    设置为OFF 表示不记录log4j2本身的日志,
 -->
<!--
status:用来指定log4j本身的打印日志级别,
monitorInterval:指定log4j自动重新配置的监测间隔时间
-->
<Configuration status="DEBUG">
    <Properties>
        <Property name="baseDir" value="./logs"/>
        <Property name="baseDir_temp" value="${sys:user.home}/logs"/>
    </Properties>

    <Appenders>
<!-- 控制台的输出配置 -->
        <Console name="Console" target="SYSTEM_OUT">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
            <ThresholdFilter level="ALL" onMatch="ACCEPT" onMismatch="DENY"/>
            <!--输出日志的格式-->
            <PatternLayout pattern="[%d{HH:mm:ss}] [%-5level] [%l{36}]:  %msg%n"/>
        </Console>

<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用-->
        <!--<File name="log" fileName="${baseDir}/temp.log" append="false">
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%l{36}]:  %msg%xEx%n"/>
        </File>-->

<!-- info+warn 级别日志文件输出 -->
        <RollingFile name="info_appender" fileName="${baseDir}/info.log"
                     filePattern="${baseDir}/$${date:yyyy-MM}/info_%d{yyyy-MM-dd}_%i.log.gz">
            <!-- 过滤器 -->
            <Filters>
                <!-- 限制日志级别在info及以上在error以下 -->
                <ThresholdFilter level="info"/>
                <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <!-- 日志格式 -->
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%-5level] [%l{36}] %m%n"/>
            <!-- 策略 -->
            <Policies>
                <!-- 每隔一天转存 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 文件大小 -->
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

<!--debug级别日志文件输出-->
        <RollingFile name="debug_appender" fileName="${baseDir}/debug.log"
                     filePattern="${baseDir}/$${date:yyyy-MM}/debug_%d{yyyy-MM-dd}_%i.log.gz">
            <!-- 过滤器 -->
            <Filters>
                <!-- 限制日志级别在debug及以上在info以下 -->
                <ThresholdFilter level="debug"/>
                <ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <!-- 日志格式 -->
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%-5level] [%l{36}] %m%n"/>
            <!-- 策略 -->
            <Policies>
                <!-- 每隔一天转存 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 文件大小 -->
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

<!-- error级别日志文件输出 -->
        <RollingFile name="error_appender" fileName="${baseDir}/error.log"
                     filePattern="${baseDir}/$${date:yyyy-MM}/error_%d{yyyy-MM-dd}_%i.log.gz">
            <!-- 过滤器 -->
            <Filters>
                <!-- 限制日志级别在error及以上 -->
                <ThresholdFilter level="error"/>
            </Filters>
            <!-- 日志格式 -->
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%-5level] [%l{36}] %m%n"/>
            <Policies>
                <!-- 每隔一天转存 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 文件大小 -->
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

    </Appenders>

    <!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。-->
    <!--然后定义loggers,只有定义了logger并引入的appender,appender才会生效-->
    <Loggers>
        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
        <logger name="org.mybatis" level="info" additivity="false">
            <AppenderRef ref="Console"/>
        </logger>
        <!--监控系统信息-->
        <!--若是additivity设为false,则 子Logger 只会在自己的appender里输出,而不会在 父Logger 的appender里输出。-->
        <Logger name="org.springframework" level="info" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>

        <Root level="info">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="info_appender"/>
            <AppenderRef ref="debug_appender"/>
            <AppenderRef ref="error_appender"/>
        </Root>

    </Loggers>
</Configuration>

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

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

相关文章

【深度学习】深度学习模型的加密及解密方案及源码

本文摘要 本文主要根据自己遇到的情况,例如:对于yolo或paddle训练的模型文件,对外使用,不想要别人拿到我的模型文件随意乱用,此时就涉及到对模型文件进行加密与解密 深度学习模型的加密保护非常重要,尤其在商业应用场景下。常见的模型加密方法包括模型文件加密、加密硬件…

图像分割基本知识

计算机视觉和图像处理 Tensorflow入门深度神经网络图像分类目标检测图像分割 图像分割 一、目标分割1.1 图像分割的定义1.2 任务类型1.2.1 任务描述1.2.2 任务类型 二、语义分割2.1 FCN网络2.1.1网络结构 2.2 Unet网络 三、UNet案例3.1 数据集获取3.1.1 设置相关信息3.1.2 图像…

nature communications |多层次蛋白质组分析揭示弥漫型和肠型胃癌之间的分子多样性

文章信息 发表期刊&#xff1a;nature communications 发表日期&#xff1a;2023年2月14日 影响因子&#xff1a;14.7 研究背景 胃癌是世界上主要的癌症类型之一。弥漫型胃癌(DGC)和肠型胃癌(IGC)是胃癌(GC)的主要组织学类型&#xff0c;DGC呈分散的细胞组织&#xff0c;黏…

比特币10年价格数据(2014-2024)分析(进阶2_时间序列分析)

数据入口&#xff1a;【每周挑战】比特币10年价格数据可视化和量化分析 - Heywhale.com 本数据集包含 2014 - 2024 的比特币美元价格数据&#xff0c;具体包含比特币每日的开盘价、最高价、最低价、收盘价以及成交量等关键信息。数据说明如下&#xff1a; 字段说明Date日期&a…

iPhone 16系列:摄影艺术的全新演绎,探索影像新境界

在科技的浪潮中&#xff0c;智能手机摄影功能的进化从未停歇。 苹果公司即将推出的iPhone 16系列&#xff0c;以其卓越的相机升级和创新特性&#xff0c;再次站在了手机摄影的前沿。 从硬件到软件&#xff0c;从拍照体验到图像处理&#xff0c;iPhone 16系列都展现了其在移动…

camtasia2024绿色免费安装包win+mac下载含2024最新激活密钥

Hey, hey, hey&#xff01;亲爱的各位小伙伴&#xff0c;今天我要给大家带来的是Camtasia2024中文版本&#xff0c;这款软件简直是视频制作爱好者的福音啊&#xff01; camtasia2024绿色免费安装包winmac下载&#xff0c;点击链接即可保存。 先说说这个版本新加的功能吧&#…

Mapsui:一个 .NET 开源的地图组件库

前言 今天大姚给大家分享一个.NET开源&#xff08;MIT License&#xff09;、免费、同时支持多平台框架&#xff08;MAUI、WPF、Avalonia、Uno、Blazor、WinUI、Eto、.NET Android 和 .NET iOS&#xff09;地图组件库&#xff1a;Mapsui。 项目源代码 支持的UI框架的NuGet包 创…

华为OD机试 - 查字典(Python/JS/C/C++ 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

【研发日记】嵌入式处理器技能解锁(六)——ARM的Cortex-M4内核

文章目录 前言 背景介绍 指令集架构 ARM起源 ARM分类 Cortex-M4 内核框架 指令流水线 实践应用 总结 参考资料 前言 见《【研发日记】嵌入式处理器技能解锁(一)——多任务异步执行调度的三种方法》 见《【研发日记】嵌入式处理器技能解锁(二)——TI C2000 DSP的SCI(…

管理依赖版本-maven工程parent项目巧配置

本文目标&#xff1a;开发人员&#xff0c;在了解pom文件properties、dependencyManagement标签用法的条件下&#xff0c;进行依赖包版本统一维护&#xff0c;达到统一维护项目依赖jar包版本的程度。 文章目录 1 场景2 要点3 总结/练习 1 场景 maven工程多模块项目&#xff0c;…

数据库基础知识---------------------------(2)

MYSQL的存储过程 就是数据库 SQL 语言层面的代码封装与重用 语法格式 delimiter 自定义结束符号 create procedure 存储名({in,out,inout} 参数名,数据类型...) begin sql 语句 end 自定义结束符 delimiter; 变量定义 局部变量 用户自定义 仅在begin / end 块中有效 当将查询…

高效开发,从暗藏玄机的文件系统开始—合宙Air201资产定位模组LuatOS

超低功耗、精准定位、快速量产——迷你小巧的合宙Air201&#xff0c;正给越来越多的行业客户带来高效开发体验。 4G-Cat.1模组的文件系统关乎数据传输速度、存储效率&#xff0c;以及数据安全性等等诸多因素&#xff0c;在应用开发中极为重要。 本期&#xff0c;我们来学习合…

微型导轨在3D打印设备中的应用与实践

微型导轨的应用范围非常广泛&#xff0c;尤其在追求高精度、高效率及低噪音的现代打印技术中扮演着重要角色。微型导轨在3D打印机等精密设备中是常用元件&#xff0c;以提高打印质量和效率。 在打印机中&#xff0c;无论是喷墨式、激光式还是3D打印机&#xff0c;都需要精确的打…

JDBC编程详细总结

一、JDBC编程 JDBC编程有标准步骤(八股文) 注册驱动 将sql语句的运行环境加载到JVM 连接数据库 获得执行SQL的对象 执行SQL语句,获得结果 关流 1、 注册驱动 Class.forName("com.mysql.jdbc.Driver");//5.7版本 加载驱动 Class.forName("com.mysql.cj.jdb…

为什么收录是谷歌seo的底子?

收录是谷歌SEO的基础&#xff0c;因为它决定了网站页面能否被用户找到。只有被谷歌收录的页面&#xff0c;才有机会在搜索结果中出现。如果页面没有被收录&#xff0c;谷歌根本就不知道它的存在&#xff0c;这意味着即使内容再好、关键词再精准&#xff0c;也不会有任何排名 被…

fo-dicom,第一个基于.NET Standard 2.0 开发的DICOM开源库

1. 简介&#xff1a; fo-dicom是一个基于C#开发的库&#xff0c;用于处理DICOM&#xff08;Digital Imaging and Communications in Medicine&#xff09;格式的数据。DICOM是一种用于医学影像和相关信息的标准格式&#xff0c;广泛应用于医学领域。fo-dicom提供了多平台支持&…

华为OD机试 - 报数问题 - 约瑟夫环(Python/JS/C/C++ 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

浸没边界法精度相关的论文的阅读笔记

Convergence proof of the velocity field for a stokes flow immersed boundary method https://doi.org/10.1002/cpa.20233 研究对象的选取 他这里为什么能够选取一个周期性边界的流场啊&#xff1f;为什么不是狄利克雷边界或者诺伊曼边界&#xff1f; 方形流场的边界值 …

keil里sprintf的用法

代码&#xff1a; #include<stdio.h> int main(void) {float i-123.45;char zifu[10];sprintf(zifu,"%f",i);while(1);return 0; } 仿真结果 代码&#xff1a; #include<stdio.h> int main(void) {float i123.45;char zifu[10];sprintf(zifu,"%f…

ReKep——李飞飞团队提出的新一代机器人操作方法:基于视觉语言模型和关键点约束

前言 由于工厂、车厂的任务需求场景非常明确&#xff0c;加之自今年年初以来&#xff0c;我司在机器人这个方向的持续大力度投入(包括南京、长沙两地机器人开发团队的先后组建)&#xff0c;使得近期我司七月接到了不少来自车厂/工厂的订单&#xff0c;比如柔性上料、物料分拣、…