log4j2.xml

log4j2.xml

  • 1、log4j2.xml使用
  • 2、日志器的流程解析
    • 2.1、几个重要的类
    • 2.2、整体流程图
  • 3、部分源码
    • 3.1、通过简单例子看源码
    • 3.2、log4j2.xml配置指导

如侵权,请联系,无心侵权~
如有错误,也请指正。

1、log4j2.xml使用

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30"><properties><property name="LOG_HOME">./logs</property></properties><Appenders><!--*********************控制台日志***********************--><Console name="consoleAppender" target="SYSTEM_OUT"><!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)--><ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/><!--设置日志格式及颜色--><PatternLayoutpattern="%style{%d{ISO8601}}{bright,green} %highlight{%-5level} [%style{%t}{bright,blue}] %style{%C{}}{bright,yellow}: %msg%n%style{%throwable}{red}"disableAnsi="false" noConsoleNoAnsi="false" charset="UTF-8"/></Console><!--*********************文件日志***********************--><!--all级别日志--><RollingFile name="allFileAppender"fileName="${LOG_HOME}/all.log"<!--日志打印路径-->filePattern="${LOG_HOME}/$${date:yyyy-MM}/all-%d{yyyy-MM-dd}-%i.log"><!--设置日志格式--><PatternLayout><pattern>%d %p %C{} [%t] %m%n</pattern></PatternLayout><Policies><!-- 设置日志文件切分参数 --><!--<OnStartupTriggeringPolicy/>--><!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新--><SizeBasedTriggeringPolicy size="100MB"/><!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置--><TimeBasedTriggeringPolicy/></Policies><!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i--><DefaultRolloverStrategy max="20"/></RollingFile><!--debug级别日志--><RollingFile name="debugFileAppender"fileName="${LOG_HOME}/debug.log"filePattern="${LOG_HOME}/$${date:yyyy-MM}/debug-%d{yyyy-MM-dd}-%i.log"><Filters><!--过滤掉info及更高级别日志--><ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL"/></Filters><!--设置日志格式--><PatternLayout><pattern>%d %p %C{} [%t] %m%n</pattern></PatternLayout><Policies><!-- 设置日志文件切分参数 --><!--<OnStartupTriggeringPolicy/>--><!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新--><SizeBasedTriggeringPolicy size="100MB"/><!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置--><TimeBasedTriggeringPolicy/></Policies><!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i--><DefaultRolloverStrategy max="20"/></RollingFile><!--info级别日志--><RollingFile name="infoFileAppender"fileName="${LOG_HOME}/info.log"filePattern="${LOG_HOME}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz"><Filters><!--过滤掉warn及更高级别日志--><ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/></Filters><!--设置日志格式--><PatternLayout><pattern>%d %p %C{} [%t] %m%n</pattern></PatternLayout><Policies><!-- 设置日志文件切分参数 --><!--<OnStartupTriggeringPolicy/>--><!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新--><SizeBasedTriggeringPolicy size="100MB"/><!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置--><TimeBasedTriggeringPolicy interval="1" modulate="true"/></Policies><!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i--><!--<DefaultRolloverStrategy max="20"/>--></RollingFile><!--warn级别日志--><RollingFile name="warnFileAppender"fileName="${LOG_HOME}/warn.log"filePattern="${LOG_HOME}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz"><Filters><!--过滤掉error及更高级别日志--><ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/></Filters><!--设置日志格式--><PatternLayout><pattern>%d %p %C{} [%t] %m%n</pattern></PatternLayout><Policies><!-- 设置日志文件切分参数 --><!--<OnStartupTriggeringPolicy/>--><!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新--><SizeBasedTriggeringPolicy size="100MB"/><!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置--><TimeBasedTriggeringPolicy/></Policies><!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i--><DefaultRolloverStrategy max="20"/></RollingFile><!--error及更高级别日志--><RollingFile name="errorFileAppender"fileName="${LOG_HOME}/error.log"filePattern="${LOG_HOME}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz"><!--设置日志格式--><PatternLayout><pattern>%d %p %C{} [%t] %m%n</pattern></PatternLayout><Policies><!-- 设置日志文件切分参数 --><!--<OnStartupTriggeringPolicy/>--><!--设置日志基础文件大小,超过该大小就触发日志文件滚动更新--><SizeBasedTriggeringPolicy size="100MB"/><!--设置日志文件滚动更新的时间,依赖于文件命名filePattern的设置--><TimeBasedTriggeringPolicy/></Policies><!--设置日志的文件个数上限,不设置默认为7个,超过大小后会被覆盖;依赖于filePattern中的%i--><DefaultRolloverStrategy max="20"/></RollingFile><!--json格式error级别日志--><RollingFile name="errorJsonAppender"fileName="${LOG_HOME}/error-json.log"filePattern="${LOG_HOME}/error-json-%d{yyyy-MM-dd}-%i.log.gz"><JSONLayout compact="true" eventEol="true" locationInfo="true"/><Policies><SizeBasedTriggeringPolicy size="100MB"/><TimeBasedTriggeringPolicy interval="1" modulate="true"/></Policies></RollingFile><!--日志远程上报--><Scribe name="ScribeAppender"><!--表示远程日志,打到远程。原理:日志先保存到kafka中,其他日志中心再消费Kafka消息。--><!--远程日志默认使用appkey作为日志名(app.properties文件中的app.name字段),也可自定义scribeCategory属性,scribeCategory优先级高于appkey--><Property name="scribeCategory">123</Property><LcLayout/></Scribe><!--将ScribeAppender和remoteErrorLog两个远程日志变成异步的--><Async name="ScribeAsyncAppender" blocking="false"><AppenderRef ref="ScribeAppender"/></Async></Appenders><Loggers><logger name="org.springframework" level="info"/><logger name="org.mybatis" level="info"/><logger name="org.apache" level="info"/><logger name="scribeLogger" level="info" additivity="false"> <!-- 如果代码中使用scribeLogger,表示这个日志往ScribeAsyncAppender这个远程日志上打 --><appender-ref ref="ScribeAsyncAppender" /></logger><!-- 根日志设置 --><Root level="INFO"><AppenderRef ref="allFileAppender" level="all"/><AppenderRef ref="consoleAppender" level="debug"/><AppenderRef ref="debugFileAppender" level="debug"/><AppenderRef ref="infoFileAppender" level="info"/><AppenderRef ref="warnFileAppender" level="warn"/><AppenderRef ref="errorFileAppender" level="error"/><AppenderRef ref="errorJsonAppender" level="error"/></Root></Loggers></Configuration>

说明:

  • additivity:非必填,默认true。该Logger是否附加给Root(此参数详细介绍看)
    子Logger 是否继承 父Logger 的 输出源(appender)的标志位。具体说,默认情况下子Logger会继承父Logger的appender,也就是说子Logger会在父Logger的appender里输出。(总之一句话,additivity=true时候,不仅会在该日志器打印一遍,而且还会在root中的所有appender中打印一遍)

以下配置了<Root>并将其打印级别设置为info,因此上面的name为"test"的<Logger>的additivity属性必须设置为false,就不会反馈到 <Root> 中;否则"apiLog"的Appender的info级别上的日志,将分别在<Logger name=“test”>和<Root>中被打印两次。

<Loggers><Logger name="test" level="trace" additivity="false"><AppenderRef ref="apiLog"/></Logger><Root level="info"><AppenderRef ref="apiLog"/><AppenderRef ref="errLog"/></Root>
</Loggers>
  • 不要往监控平台打印过多的数据,例如美团的Raptor。日志中心是用来记录和展示业务日志的,什么日志都能往里放。
  • 在日志器中会有level,表示这个日志器只会打印大于等于该level的日志,而appender中也可以配置<ThresholdFilter>level=xxx</ThresholdFilter>,表示该appender只会打印大于等于xxx的日志。因此这两个是要同时满足。举例:
    配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="info"><appenders><Console name="Console" target="SYSTEM_OUT" follow="true"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %t %-5level %logger{30}.%method - %ex %msg%n" /><Filters><ThresholdFilter level="error" onMatch="DENY" onMismatch="ACCEPT"/></Filters></Console><loggers><root level="info"><appender-ref ref="Console" /></root></loggers>
</configuration>

Java程序:

@Slf4j
public class Log4j2Test {@Testpublic void testLevel(){log.trace("trace level");log.debug("debug level");log.info("info level");log.warn("warn level");log.error("error level");}
}

结果:日志器root可以输出info级别及以上的,但是console appender不输出error级别及以上的,所以只输出了info warn级别的日志。因此两者取交集。

2022-12-28 19:47:34.436 main INFO  com.sankuai.mdp.fanjunfu.Log4j2Test.testLevel -  info level
2022-12-28 19:47:34.442 main WARN  com.sankuai.mdp.fanjunfu.Log4j2Test.testLevel -  warn level
  • RollingFile标签是日志打印到本地机器。

2、日志器的流程解析

2.1、几个重要的类

日志的门面类:
接口:org.slf4j的Logger(slfj4j:The Simple Logging Facade for Java)

package org.slf4j;public interface Logger {// 获取日志器的名字public String getName();// 日志器是否开启了trace级别的日志打印public boolean isTraceEnabled();// 以trace级别进行打印日志,该方法多种重载public void trace(String msg);// 下面和trace含义一样,只是日志打印级别不一样public boolean isDebugEnabled();public void debug(String msg);public boolean isInfoEnabled();public void info(String msg);public boolean isWarnEnabled();public void warn(String msg);public boolean isErrorEnabled();public void error(String msg);}

实现:org.apache.logging.slf4j.Log4jLogger

日志的实现:
org.apache.logging.log4j的Logger

public interface Logger {boolean isTraceEnabled();void trace(Message message);boolean isInfoEnabled();void info(Message message);boolean isDebugEnabled();void debug(Message message);boolean isWarnEnabled();void warn(Message message);boolean isErrorEnabled();void error(Message message);boolean isFatalEnabled();void fatal(Message message);// 以指定的级别进行打印void log(Level level, Message message);
}

org.apache.logging.log4j.spi的ExtendedLogger

package org.apache.logging.log4j.spi;import org.apache.logging.log4j.Logger;public interface ExtendedLogger extends Logger {// 日志日否开启boolean isEnabled(Level level, Marker marker, Message message, Throwable t);// 如果日志开启,打印日志void logIfEnabled(String fqcn, Level level, Marker marker, CharSequence message, Throwable t);}

org.apache.logging.log4j.spi的AbstractLogger是ExtendedLogger的实现类

继承图:
在这里插入图片描述

调用图:
在这里插入图片描述

2.2、整体流程图

在这里插入图片描述
主线程或者工作线程只是调用到各种appender,如AsyncAppender/consoleAppender,会把日志数据存储到BlockingQueue队列中,BlockingQueue队列大小为1024。如果超过1024(日志打印过多导致同步日志器消费赶不上生产速度),这个阻塞队列就放不下,就会放到StatusLogger的BoundedQueue(这个作用为了日志的有序性?)并且类似于StatusConsoleListener的监听器进行打印输出(这里是同步的,大量使用了synchronized)。

在AsyncAppender的BlockingQueue之后仍然使用主线程/工作线程执行后面的逻辑DefaultErrorHandler的逻辑,而这里会有大量的同步代码块synchronized,从而导致主线程/工作线程阻塞。

这些出现大量同步的地方都是可以优化的地方,提供系统的吞吐量。

PrintStream会把信息打印到控制台Console.
在这里插入图片描述
代码简述逻辑:

  • 通过name获得日志器Logger
  • 调用日志器的callAppender()方法
  • callAppender()方法会调用这个日志器下面所有的appender-ref的appender.append()
  • 具体就看这个append()的实现:
    • 同步日志器ScribeLogger: 进行socket.connect()远程连接,然后发送数据
    • 异步步日志器AsyncScribeLogger: 存放到阻塞队列,然后开启一个子线程,将阻塞队列中的日志数据分发给异步日志器所有的appender-ref
    • 本地日志器XMDScribeLogger: 存放到阻塞队列,然后开启一个子线程,将阻塞队列中的日志数据分发给新创建的一个AppendRollingAppender(存储到本地机器)

3、部分源码

3.1、通过简单例子看源码

log4j2.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="info"><appenders><Console name="Console" target="SYSTEM_OUT" follow="true"><!--<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %t %-5level %logger{30}.%method - %msg%n" />--><PatternLayout pattern="%5p %d{yyyy-MM-dd HH:mm:ss} %c %L Line - %m %n" /></Console><!--默认按天&按512M文件大小切分日志,默认最多保留30个日志文件,非阻塞模式--><XMDFile name="infoAppender" fileName="info.log" sizeBasedTriggeringSize="512M"rolloverMax="30"><Filters><ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/><ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/></Filters></XMDFile><XMDFile name="warnAppender" fileName="warn.log" sizeBasedTriggeringSize="512M"rolloverMax="30"><Filters><ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/><ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/></Filters></XMDFile><XMDFile name="errorAppender" fileName="error.log" sizeBasedTriggeringSize="512M"rolloverMax="30"><ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/><PatternLayout><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} - - [%p] %t %c{1.} %XMDT (%F:%L) %msg%n</pattern></PatternLayout></XMDFile><!--日志远程上报--><Scribe name="ScribeAppender"><!--远程日志默认使用appkey作为日志名(app.properties文件中的app.name字段),也可自定义scribeCategory属性,scribeCategory优先级高于appkey--><Property name="scribeCategory">wpt_aggroupapi_tracelog</Property><LcLayout/></Scribe><Scribe name="remoteErrorLog"><ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/><LcLayout/></Scribe><Async name="ScribeAsyncAppender" blocking="false"><AppenderRef ref="ScribeAppender"/><AppenderRef ref="remoteErrorLog"/></Async><CatAppender name="catAppender"/></appenders><loggers><!--远程日志,详细使用说明参见 MDP 文档中日志中心部分 https://docs.sankuai.com/dp/hbar/mdp-docs/master/log/#2 --><logger name="scribeLogger" level="info" additivity="false"><appender-ref ref="ScribeAsyncAppender" /></logger><logger name="org.springframework" level="info" additivity="false"><appender-ref ref="Console" /></logger><root level="info"><appender-ref ref="infoAppender"/><appender-ref ref="warnAppender"/><appender-ref ref="errorAppender"/><appender-ref ref="Console" /><appender-ref ref="catAppender"/></root></loggers>
</configuration>

代码:

public class Test {private final static Logger log =  LoggerFactory.getLogger("scribeLogger");@Testpublic void test(){System.out.println("start~");log.error("hello {} ! ", "word");System.out.println("end!");}
}

源码:
LoggerConfig:

public class LoggerConfig extends AbstractFilterable implements LocationAware {private void processLogEvent(final LogEvent event, final LoggerConfigPredicate predicate) {event.setIncludeLocation(isIncludeLocation());if (predicate.allow(this)) {callAppenders(event);   // 调用所有的appender}logParent(event, predicate);}protected void callAppenders(final LogEvent event) {final AppenderControl[] controls = appenders.get();//noinspection ForLoopReplaceableByForEachfor (int i = 0; i < controls.length; i++) {controls[i].callAppender(event);  // 调用这个日志器下面的appender-ref(appender)}}
}

AppendControl

public class AppenderControl extends AbstractFilterable {private void tryCallAppender(final LogEvent event) {try {appender.append(event);   // 无论是AsynAppender还是XMDFileAppender,该方法都是存储到他们内部的阻塞队列中BlockingQueue} catch (final RuntimeException error) {handleAppenderError(event, error);} catch (final Throwable throwable) {handleAppenderError(event, new AppenderLoggingException(throwable));}}
}

AsynAppender

public final class AsyncAppender extends AbstractAppender {// 在启动的时候,会调用该方法public void start() {final Map<String, Appender> map = config.getAppenders();final List<AppenderControl> appenders = new ArrayList<>();for (final AppenderRef appenderRef : appenderRefs) {final Appender appender = map.get(appenderRef.getRef());if (appender != null) {appenders.add(new AppenderControl(appender, appenderRef.getLevel(), appenderRef.getFilter()));} else {LOGGER.error("No appender named {} was configured", appenderRef);}}if (errorRef != null) {final Appender appender = map.get(errorRef);if (appender != null) {errorAppender = new AppenderControl(appender, null, null);} else {LOGGER.error("Unable to set up error Appender. No appender named {} was configured", errorRef);}}if (appenders.size() > 0) {dispatcher = new AsyncAppenderEventDispatcher(  // 这个类是一个线程继承Thread,这个类会从AsyncAppender的阻塞队列中获取数据,分发dispatch给appenders(这个是这个异步日志器下的appender(一般为同步日志器,同步日志器会通过socket.connect与远程日志器连接、发送))getName(), errorAppender, appenders, queue);  // 异步日志器的所有同步日志器会消费这个阻塞队列queue(该线程进行分配)} else if (errorRef == null) {throw new ConfigurationException("No appenders are available for AsyncAppender " + getName());}asyncQueueFullPolicy = AsyncQueueFullPolicyFactory.create();dispatcher.start();  // 启动该线程super.start();}
}

AsyncAppenderEventDispatcher

class AsyncAppenderEventDispatcher extends Log4jThread {@Overridepublic void run() {LOGGER.trace("{} has started.", getName());dispatchAll();dispatchRemaining();}private void dispatchAll() {while (!stoppedRef.get()) {LogEvent event;try {event = queue.take();  // } catch (final InterruptedException ignored) {// Restore the interrupted flag cleared when the exception is caught.interrupt();break;}if (event == STOP_EVENT) {break;}event.setEndOfBatch(queue.isEmpty());dispatch(event);   // 分发给这个日志的appender进行执行}LOGGER.trace("{} has stopped.", getName());}void dispatch(final LogEvent event) {// Dispatch the event to all registered appenders.boolean succeeded = false;// noinspection ForLoopReplaceableByForEach (avoid iterator instantion)for (int appenderIndex = 0; appenderIndex < appenders.size(); appenderIndex++) {final AppenderControl control = appenders.get(appenderIndex);try {control.callAppender(event);succeeded = true;} catch (final Throwable error) {// If no appender is successful, the error appender will get it.// It is okay to simply log it here.LOGGER.trace("{} has failed to call appender {}",getName(), control.getAppenderName(), error);}}// Fallback to the error appender if none has succeeded so far.if (!succeeded && errorAppender != null) {try {errorAppender.callAppender(event);} catch (final Throwable error) {// If the error appender also fails, there is nothing further// we can do about it.LOGGER.trace("{} has failed to call the error appender {}",getName(), errorAppender.getAppenderName(), error);}}}
}

3.2、log4j2.xml配置指导

  1. 建议日志配置文件中对所有Appender的PatternLayout都增加%ex配置,因为如果没有显式配置%ex,则异常格式化输出的默认配置是%xEx,此时会打印异常的扩展信息(jar名称和版本),可能导致业务线程Block。
  2. 不建议日志配置文件中使用AsyncAppender,建议自定义Appender实现,因为AsyncAppender是日志框架默认提供的,目前最新版本中仍然存在日志事件入队前就加载异常堆栈类的问题,可能导致业务线程Block。
  3. 不建议生产环境使用ConsoleAppender,因为输出日志到Console时有synchronized同步操作,高并发场景下非常容易导致业务线程Block。
  4. 不建议在配置文件中使用<AsyncLogger>标签,因为日志事件元素在入队前就会触发加载异常堆栈类,可能导致业务线程Block。如果希望使用Log4j2提供的异步日志AsyncLogger,建议配置Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector参数,开启异步日志。

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

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

相关文章

Anaconda虚拟环境安装cuda和pytorch

首先电脑上要有Anaconda&#xff0c;使用conda创建一个虚拟环境,并激活 conda create yolov8 conda activate yolov8winR输入cmd&#xff0c;在命令窗口输入 NVIDIA-smi可以查看到自己电脑支持的cuda环境&#xff0c;如下图 再打开torch的官网 pytorch官网 查看目前支持的版…

目标检测——Cascade R-CNN算法解读

论文&#xff1a; Cascade R-CNN: Delving into High Quality Object Detection (2017.12.3) 链接&#xff1a;https://arxiv.org/abs/1712.00726 Cascade R-CNN: High Quality Object Detection and Instance Segmentation (2019.6.24) 链接&#xff1a;https://arxiv.org/abs…

Z 字形变换(6)

这道题之前一直不会做&#xff0c;明白他是什么意思&#xff0c;但是找不到方法或者方法过于繁琐 方法1&#xff1a; 这是我在力扣评论区看到的方法&#xff0c;太精彩了。 虽然我实现起来效率并不高&#xff0c;可能是我代码的问题&#xff0c;但是他的思路很巧妙。 字符串的…

Spring--1

spring是一个轻量级的&#xff0c;采用IOC与AOP编程思想的java后端开发框架&#xff0c;简化了企业级的应用开发。 Spring体系 数据访问层&#xff0c;Web层&#xff0c;配置中心&#xff0c;测试区 IOC 控制反转&#xff0c;将创建对象的控制权交由Spring框架&#xff0c;需…

音频分割:长语音音频 分割为 短语音音频 - python 实现

在做语音任务时&#xff0c;有是会用到的语音音频是长音频&#xff0c;这就需要我们将长音频分割为短音频。 该示例将声音的音量和静默时间结合作为语音的分割条件。 使用音量和静默时间结合的分割条件&#xff0c;能够比较好的进行自然断句&#xff0c;不会话语没有说完就切断…

Spring声明式事务管理:深入探索XML配置方式

前言 Spring的事务管理&#xff0c;无论是基于xml还是注解实现&#xff0c;本质上还是实现数据库的事务管理机制&#xff0c;因此要注意发送SQL的连接是否为同一个&#xff0c;这是实现声明式事务的关键。 以下案例和实现基于SSM整合框架完成&#xff0c;不知道如何整合SSM&…

【K8S系列】Kubernetes Pod 状态详细介绍及异常状态解决方案

在 Kubernetes 中&#xff0c;Pod 是最小的可调度单元&#xff0c;负责运行一个或多个容器。Pod 的状态能够反映其生命周期中的不同阶段&#xff0c;帮助用户了解当前的运行状况。本文将详细介绍 Kubernetes Pod 的各种状态及其可能的异常状态解决方案。 一、Pod 状态概览 Po…

查缺补漏----数据结构树高总结

① 对于平衡二叉树而言&#xff0c;树高的规律&#xff1a; 高度为h的平衡二叉树的含有的最少结点数&#xff08;所有非叶节点的平衡因子均为1&#xff09;&#xff1a; n01&#xff0c;n11&#xff0c;n22 含有的最多结点数&#xff1a; (高度为h的满二叉树含有的结点数) ②…

Flutter在 iOS 中实现无弹窗获取剪切板内容

前言 在最新的项目需求中&#xff0c;我们需要在获取剪切板内容时避免弹出授权提示。这一功能是基于竞品的实现&#xff0c;旨在优化用户体验&#xff0c;特别是在推广获取跳转链接的场景下非常有用。 解决方案 通过查阅资料&#xff0c;我们发现对于 iOS 16 及以上的系统&a…

Fusion创建一个简单的api脚本文件

我的Fusion版本&#xff1a;Fusion 2.0.20476 x86_64 脚本模块在实用程序->附加模型->脚本和附加模块&#xff0c;快捷键为shifts 里面有一些演示脚本&#xff0c;可以直接使用 也可以自己创建一个新的脚本 创建的脚本在此处—— 选择脚本文件&#xff0c;点击编辑&a…

Unity Mirror NetworkManager初识

文章目录 Network Manager网络管理器什么是网络管理器&#xff1f;通过Transports进行定制化网络连接管理自定义连接地址和端口号Game State Management游戏状态管理Network Manager HUD玩家预制体及其生成控制Spawn Prefabs其他预制体注册Scene Management场景管理 Network Ma…

在Windows系统中,cmd 查看 MongoDB 相关信息

MongoDB是一种流行的NoSQL数据库&#xff0c;广泛应用于各种现代应用程序中。 1 查看MongoDB的版本号 要查看MongoDB的版本号&#xff0c;可以使用mongo命令连接到MongoDB&#xff0c;然后执行db.version()。 mongo连接到数据库后&#xff0c;执行以下命令&#xff0c;输出M…

读数据工程之道:设计和构建健壮的数据系统16源系统实际细节(下)

1. 数据共享 1.1. 云数据共享的核心概念是&#xff0c;多租户系统支持租户之间共享数据的安全策略 1.2. 任何具有细粒度权限系统的公有云对象存储系统都可以成为数据共享的平台 1.3. 数据共享也简化了数据市场的概念&#xff0c;在几个流行的云和数据平台上都可用 1.4. 数据…

RabbitMQ系列学习笔记(三)--工作队列模式

文章目录 一、工作队列模式原理二、工作队列模式实战1、抽取工具类2、消费者代码3、生产者代码4、查看运行结果 本文参考 尚硅谷RabbitMQ教程丨快速掌握MQ消息中间件rabbitmq RabbitMQ 详解 Centos7环境安装Erlang、RabbitMQ详细过程(配图) 一、工作队列模式原理 与简单模式相…

SpringBoot篇(二、制作SpringBoot程序)

目录 一、代码位置 二、四种方式 1. IDEA联网版 2. 官网 3. 阿里云 4. 手动 五、在IDEA中隐藏指定文件/文件夹 六、复制工程-快速操作 七、更改引导类别名 一、代码位置 二、四种方式 1. IDEA联网版 2. 官网 官网制作&#xff1a;Spring Boot 3. 阿里云 阿里云版制…

基于SSM+微信小程序的家庭记账本管理系统(家庭1)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 1、管理员端功能有首页、个人中心、用户管理&#xff0c;消费详情管理、收入详情管理、系统管理等。 2、用户端功能有首页、消费详情、收入详情、论坛信息、我的等功能。 2、项目技术 …

django5入门【02】创建新的django程序

注意&#xff1a; ⭐前提&#xff1a;已经安装了python以及django所依赖的包1、通过django-admin管理工具在命令行创建Django应用程序&#xff0c;创建命令如下&#xff1a; django-admin startproject ProjectName❓ 疑问&#xff1a;除了使用命令行创建django程序外&#x…

OCR经典神经网络(三)LayoutLM v2算法原理及其在发票数据集上的应用(NER及RE)

OCR经典神经网络(三)LayoutLM v2算法原理及其在发票数据集上的应用(NER及RE) LayoutLM系列模型是微软发布的、文档理解多模态基础模型领域最重要和有代表性的工作&#xff1a; LayoutLM v2&#xff1a;在一个单一的多模态框架中对文本&#xff08;text&#xff09;、布局&…

eQEP正交解码

目录 基本介绍 整体框架 关键模块 编译问题 实验效果 基本介绍 编码器是一种将角位移或者角速度转换成一连串电数字脉冲的旋转式传感器&#xff0c;我们可以通过编码器测量到位移或者速度信息。编码器从输出数据类型上分&#xff0c;可以分为增量式编码器和绝对式编码器。…

深入浅出MySQL:概述与体系结构解析

目录 1. 初识MySQL1.1. 数据库1.1.1. OLTP&#xff08;联机事务处理&#xff09;1.1.2. OLAP&#xff08;联机分析处理&#xff09; 2. SQL2.1. 定义2.2. DQL&#xff08;数据查询语言&#xff09;2.3. DML&#xff08;数据操纵语言&#xff09;2.4. DDL&#xff08;数据定义语…