日志是应用程序不可或缺的组成部分,它不仅能帮助我们调试问题,还能监控系统运行状态。在 Spring Boot 生态中,Logback 凭借其高性能和灵活性成为首选的日志框架。本文将通过一个实际的 Logback 配置文件,详细解析其各个组件的功能和配置技巧。

什么是 Logback?

Logback 是由 Log4j 创始人设计的开源日志组件,是 Log4j 的继任者。它分为三个模块:

  • logback-core:核心组件,提供基础功能
  • logback-classic:实现了 SLF4J API,可直接替换 Log4j
  • logback-access:与 Servlet 容器集成,提供 HTTP 访问日志功能

在 Spring Boot 中,Logback 是默认的日志框架,无需额外依赖即可使用。

完整配置文件解析

<?xml version="1.0" encoding="UTF-8"?>
<!--Copyright 2010-2011 The myBatis TeamLicensed under the Apache License, Version 2.0 (the "License");you may not use this file except in compliance with the License.You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed under the License is distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions andlimitations under the License.
-->
<configuration debug="false"><!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径--><springProperty scope="context" name="LOG_HOME" source="HuiChen.log.directory"/><springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="huichen-device-sms-manager"/><springProperty scope="context" name="LOG_LEVEL" source="HuiChen.log.level" defaultValue="debug"/><!-- 彩色日志 --><!-- 彩色日志依赖的渲染类 --><conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/><conversionRule conversionWord="wex"converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/><conversionRule conversionWord="wEx"converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/><!-- 彩色日志格式 --><property name="CONSOLE_LOG_PATTERN"value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/><!-- Console 输出设置 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--        <encoder>-->
<!--            <pattern> ${CONSOLE_LOG_PATTERN}</pattern>-->
<!--            <charset>utf8</charset>-->
<!--        </encoder>--><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"><pattern>[%tid] ${CONSOLE_LOG_PATTERN}</pattern></layout><charset>utf-8</charset></encoder></appender><!-- 按照每天生成INFO日志文件 --><appender name="FILEINFO" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!--日志文件输出的文件名--><FileNamePattern>${LOG_HOME}/${APP_NAME}.%d{yyyy-MM-dd}.info.%i.log</FileNamePattern><!--日志文件保留天数--><MaxHistory>30</MaxHistory><!--日志文件最大的大小--><MaxFileSize>10MB</MaxFileSize></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder></appender><!-- 按照每天生成ERROR日志文件 --><appender name="FILEERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!--日志文件输出的文件名--><FileNamePattern>${LOG_HOME}/${APP_NAME}.%d{yyyy-MM-dd}.error.%i.log</FileNamePattern><!--日志文件保留天数--><MaxHistory>30</MaxHistory><!--日志文件最大的大小--><MaxFileSize>10MB</MaxFileSize></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder><!-- 此日志文件只记录info级别的 --><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>error</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter></appender><!-- skywalking 采集日志 --><appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender"><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout"><Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</Pattern></layout></encoder></appender><!--myibatis mongodb log configure--><logger name="com.apache.ibatis" level="TRACE"/><logger name="java.sql.Connection" level="DEBUG"/><logger name="java.sql.Statement" level="DEBUG"/><logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!--    <logger name="org.springframework.data.mongodb.core" level="DEBUG"/><logger name="org.springframework.data.redis.core" level="DEBUG"/><logger name="org.springframework.data.elasticsearch" level="DEBUG"/><logger name="org.springframework.data.neo4j" level="DEBUG"/>--><logger name="com.sms.manager" level="DEBUG"/><!-- 日志输出级别 INFO--><root level="${LOG_LEVEL}"><appender-ref ref="STDOUT"/><appender-ref ref="grpc-log"/><appender-ref ref="FILEINFO"/><appender-ref ref="FILEERROR"/></root><!--日志异步到数据库 --><!--<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">--><!--&lt;!&ndash;日志异步到数据库 &ndash;&gt;--><!--<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">--><!--&lt;!&ndash;连接池 &ndash;&gt;--><!--<dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">--><!--<driverClass>com.mysql.jdbc.Driver</driverClass>--><!--<url>jdbc:mysql://baas.ievent.cn:3306/ievent</url>--><!--<user>live</user>--><!--<password>novacloudlive</password>--><!--</dataSource>--><!--</connectionSource>--><!--</appender>-->
</configuration>

下面我们将逐部分解析一个生产级别的 Logback 配置文件,理解其各个组件的作用。

1. 配置文件基本结构

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false"><!-- 配置内容 -->
</configuration>
  • debug="false":关闭 Logback 自身的调试日志,生产环境建议关闭

2. 动态属性定义

<springProperty scope="context" name="LOG_HOME" source="HuiChen.log.directory"/>
<springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="huichen-device-sms-manager"/>
<springProperty scope="context" name="LOG_LEVEL" source="HuiChen.log.level" defaultValue="debug"/>

这部分配置通过 <springProperty> 标签将 Spring 环境中的配置注入到 Logback 中,实现了配置的动态化和外部化:

  • LOG_HOME:日志文件存储目录,值来自 Spring 配置的 HuiChen.log.directory
  • APP_NAME:应用名称,默认值为 huichen-device-sms-manager,可通过 spring.application.name 覆盖
  • LOG_LEVEL:全局日志级别,默认 debug,可通过 HuiChen.log.level 配置

这种方式的优势在于:

  • 可以在不同环境(开发、测试、生产)使用不同的配置
  • 无需修改 Logback 配置文件即可调整日志行为
  • 符合 Spring Boot 外部化配置的理念

3. 彩色日志配置

<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex"converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx"converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/><!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

这段配置实现了控制台彩色日志输出:

  • <conversionRule>:定义了三个转换规则,用于日志的彩色渲染和异常信息格式化
  • CONSOLE_LOG_PATTERN:定义了控制台日志的输出格式,其中:
    • %clr(...):用于指定日志元素的颜色
    • %d{...}:日期时间,格式为 yyyy-MM-dd HH:mm:ss.SSS
    • %5p:日志级别,占 5 个字符宽度
    • ${PID:- }:进程 ID
    • %15.15t:线程名,最长 15 个字符
    • %-40.40logger{39}:日志器名称,最长 40 个字符
    • %m%n:日志消息和换行符

彩色日志的优势在于:

  • 不同级别日志用不同颜色显示,便于快速识别
  • 关键信息(如线程名、类名)有颜色区分,提高可读性
  • 异常堆栈信息格式化显示,便于调试

4. 日志输出目的地(Appender)

Appender 定义了日志的输出方式和位置,一个配置文件中可以有多个 Appender。

4.1 控制台输出(STDOUT)
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"><pattern>[%tid] ${CONSOLE_LOG_PATTERN}</pattern></layout><charset>utf-8</charset></encoder>
</appender>

这是一个输出到控制台的 Appender:

  • name="STDOUT":Appender 的名称,用于后续引用
  • class="ch.qos.logback.core.ConsoleAppender":指定这是控制台输出的 Appender
  • <encoder>:编码器,负责将日志事件转换为字符串
    • LayoutWrappingEncoder:使用自定义布局的编码器
    • TraceIdPatternLogbackLayout:集成了 SkyWalking 的布局,用于添加分布式追踪 ID
    • [%tid]:SkyWalking 追踪 ID,在分布式系统中非常有用
    • charset="utf-8":日志编码格式
4.2 INFO 级别日志文件(FILEINFO)
<appender name="FILEINFO" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 日志文件输出的文件名 --><FileNamePattern>${LOG_HOME}/${APP_NAME}.%d{yyyy-MM-dd}.info.%i.log</FileNamePattern><!-- 日志文件保留天数 --><MaxHistory>30</MaxHistory><!-- 日志文件最大的大小 --><MaxFileSize>10MB</MaxFileSize></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder>
</appender>

这是一个滚动输出 INFO 级别日志到文件的 Appender:

  • class="ch.qos.logback.core.rolling.RollingFileAppender":滚动文件输出 Appender,支持日志文件分割
  • <rollingPolicy>:滚动策略,这里使用 SizeAndTimeBasedRollingPolicy,结合了时间和大小的滚动策略
    • FileNamePattern:日志文件命名规则,包含日期和序号
    • MaxHistory:日志文件保留 30 天
    • MaxFileSize:单个日志文件最大 10MB,超过则创建新文件
  • <encoder>:定义了文件日志的格式,包含日期、线程、级别、日志器和消息
4.3 ERROR 级别日志文件(FILEERROR)
<appender name="FILEERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><FileNamePattern>${LOG_HOME}/${APP_NAME}.%d{yyyy-MM-dd}.error.%i.log</FileNamePattern><MaxHistory>30</MaxHistory><MaxFileSize>10MB</MaxFileSize></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>error</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter>
</appender>

这个 Appender 专门用于记录 ERROR 级别日志:

  • 与 FILEINFO 类似,但增加了 <filter> 配置
  • LevelFilter:级别过滤器,只接受 ERROR 级别的日志
    • onMatch>ACCEPT</onMatch>:匹配 ERROR 级别则接受
    • onMismatch>DENY</onMismatch>:不匹配则拒绝

将 ERROR 日志单独存储的好处:

  • 便于快速定位错误,无需在大量日志中筛选
  • 可以设置更长的保留时间,便于问题追溯
  • 不同级别的日志可以有不同的处理策略
4.4 SkyWalking 日志采集(grpc-log)
<appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender"><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout"><Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</Pattern></layout></encoder>
</appender>

这个 Appender 用于将日志发送到 SkyWalking APM 系统:

  • GRPCLogClientAppender:通过 gRPC 协议将日志发送到 SkyWalking 服务器
  • TraceIdMDCPatternLogbackLayout:将追踪 ID 放入日志,实现分布式追踪
  • [%X{tid}]:从 MDC(Mapped Diagnostic Context)中获取追踪 ID

集成 SkyWalking 的优势:

  • 实现日志与分布式追踪的关联,便于微服务架构下的问题排查
  • 可以在 SkyWalking 控制台查看全链路日志
  • 追踪 ID 贯穿整个调用链,方便定位跨服务问题

5. 日志级别控制

<!-- myibatis mongodb log configure -->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- 
<logger name="org.springframework.data.mongodb.core" level="DEBUG"/>
<logger name="org.springframework.data.redis.core" level="DEBUG"/>
<logger name="org.springframework.data.elasticsearch" level="DEBUG"/>
<logger name="org.springframework.data.neo4j" level="DEBUG"/>
--><logger name="com.sms.manager" level="DEBUG"/><!-- 日志输出级别 -->
<root level="${LOG_LEVEL}"><appender-ref ref="STDOUT"/><appender-ref ref="grpc-log"/><appender-ref ref="FILEINFO"/><appender-ref ref="FILEERROR"/>
</root>

这部分配置控制不同包或类的日志级别:

  • <logger>:针对特定包或类设置日志级别

    • name:指定包或类的全限定名
    • level:日志级别,从低到高为 TRACE < DEBUG < INFO < WARN < ERROR
    • 例如 com.sms.manager 包下的日志被设置为 DEBUG 级别
  • <root>:根日志配置,所有未被特定 logger 配置的类都继承此配置

    • level="${LOG_LEVEL}":使用之前定义的动态属性作为全局日志级别
    • <appender-ref>:引用前面定义的 Appender,表示日志会输出到这些目的地

日志级别的作用:

  • 控制日志输出的详细程度,生产环境通常使用 INFO 级别减少日志量
  • 特定包可以设置更详细的日志级别,便于调试
  • 避免不必要的日志输出,提高系统性能

6. 数据库日志(注释部分)

配置文件中还有一个注释掉的数据库日志 Appender:

<!--
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender"><connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource"><dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource"><driverClass>com.mysql.jdbc.Driver</driverClass><url>jdbc:mysql://baas.ievent.cn:3306/ievent</url><user>live</user><password>novacloudlive</password></dataSource></connectionSource>
</appender>
-->

这个 Appender 用于将日志存储到数据库中,适用于需要对日志进行复杂查询和分析的场景。但由于性能影响和配置复杂性,通常在生产环境中不推荐使用,除非有特殊需求。

实际应用中的最佳实践

  1. 环境隔离

    • 开发环境:使用 DEBUG 级别,输出到控制台
    • 生产环境:使用 INFO 级别,输出到文件,限制日志大小和保留时间
  2. 性能考虑

    • 避免在循环中输出大量日志
    • 生产环境避免使用 DEBUG 级别
    • 适当设置日志文件大小和保留时间,避免磁盘空间耗尽
  3. 安全考虑

    • 日志中避免包含敏感信息(密码、令牌等)
    • 确保日志文件有适当的权限控制
    • 敏感操作的日志应特别关注
  4. 分布式系统

    • 集成分布式追踪系统(如 SkyWalking)
    • 确保日志中包含追踪 ID,便于跨服务追踪
    • 统一日志收集和分析(如使用 ELK 栈)

总结

本文详细解析了一个生产级别的 Logback 配置文件,涵盖了动态属性、彩色日志、多目的地输出、日志级别控制和分布式追踪集成等方面。合理配置 Logback 不仅能帮助我们更好地理解系统运行状态,还能在出现问题时快速定位和解决。

Logback 的配置灵活多变,应根据实际需求进行调整。在开发和生产环境中使用不同的配置,既能保证开发效率,又能确保生产系统的稳定运行。

希望本文能帮助你更好地理解和使用 Logback,构建更健壮的日志系统。

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

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

相关文章

软件体系结构——后端三层架构

三层架构——Controller、Service、Dao 不仅是对代码进行的逻辑分层。其真正的本质&#xff0c;是将业务、技术和数据剥离。搞业务的专心做业务&#xff0c;搞技术的专心搞技术&#xff0c;做数据存储的专心做数据存储。三方通过接口进行对接&#xff0c;任一部分重构&#xff…

QML学习笔记(一)基本了解和工程配置

前言&#xff1a; 已经从事QT开发几年了&#xff0c;但对于QML这个东西始终是没有彻底掌握&#xff0c;一方面实际工作中没有用到过&#xff0c;其次它的语法对我来说是全新的东西&#xff0c;不像QWidget那一套可以直接在C中去写。这就是为什么网上都说qml更简单&#xff0c;我…

SAP HANA Scale-out 04:缓存

结果缓存静态结果缓存 Vs 动态结果缓存FeatureStatic Result CacheDynamic Result CacheTarget Scenario对复杂视图&#xff08;通常是顶层视图&#xff09;的查询频繁更新的大表&#xff08;例如ACDOCA&#xff09;上的聚合查询Query result非实时数据实时数据ScopeTarget obj…

嘉兴禾润 HTR7216 (S) LED 驱动芯片:特性与应用

在如今智能设备飞速普及的时代&#xff0c;无论是智能家居的氛围营造、IoT 设备的状态提示&#xff0c;还是个人消费电子的视觉呈现&#xff0c;都离不开高性能 LED 驱动芯片的支撑。嘉兴禾润推出的 HTR7216 (S) LED 驱动芯片&#xff0c;凭借丰富的功能、精准的控制以及出色的…

Python实现剑龙优化算法 (Stegosaurus Optimization Algorithm, SOA)优化函数(付完整代码)

Python实现剑龙优化算法 (Stegosaurus Optimization Algorithm, SOA)优化函数&#xff08;付完整代码&#xff09;1.剑龙优化算法介绍剑龙优化算法&#xff08;Stegosaurus Optimization Algorithm&#xff0c;SOA&#xff09;是一种受剑龙独特生理结构和行为模式启发而设计的元…

分布式拜占庭容错算法——权益证明(PoS)算法详解

Java 实现权益证明&#xff08;PoS&#xff09;算法详解 一、PoS 核心机制 #mermaid-svg-Sbj0HU6MjOl1yo5L {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Sbj0HU6MjOl1yo5L .error-icon{fill:#552222;}#mermaid-s…

【论文阅读】谷歌:生成式数据优化,只需请求更好的数据

谷歌DeepMind团队通过Generative Data Refinement&#xff08;GDR&#xff09;技术&#xff0c;成功将极端有毒的4chan讨论数据转化为安全且语义丰富的训练素材&#xff0c;推动了LLM训练数据净化的新范式&#xff1a; • GDR利用预训练大模型对原始数据进行“重写”&#xff0…

C++ 多线程实战 10|C++20 的信号量、闩锁与屏障

目录 前言 学习目标 1. 信号量&#xff08;Semaphore&#xff09; 示例&#xff1a;限制并发下载任务 2. 闩锁&#xff08;Latch&#xff09; 示例&#xff1a;赛跑 3. 屏障&#xff08;Barrier&#xff09; 示例&#xff1a;图像处理流水线 4. 常见坑与对策 5. 实践作…

【Java SE】01. 初识Java

1. 认识Java Java是一种优秀的程序设计语言&#xff0c;它具有令人赏心悦目的语法和易于理解的语义。Java还是一个有一系列计算机软件和规范形成的技术体系&#xff0c;这个技术体系提供了完整的用于软件开发和跨平台部署的支持环境&#xff0c;并广泛应用于嵌入式系统、移动终…

解锁仓储智能调度、运输路径优化、数据实时追踪,全功能降本提效的智慧物流开源了

AI 视频监控平台&#xff1a;全链路协同驱动的智能监控解决方案AI 视频监控平台是一款融合高性能功能与轻量化操作的实时算法驱动型视频监控系统&#xff0c;其核心愿景在于深度破除不同芯片厂商间的技术壁垒&#xff0c;省去冗余重复的适配环节&#xff0c;最终达成芯片、算法…

冒泡排序与选择排序以及单链表与双链表

1. 冒泡排序&#xff08;Bubble Sort&#xff09; 1. 原理 冒泡排序是一种 简单的排序算法&#xff0c;通过 两两比较相邻元素&#xff0c;把较大的元素逐渐 “冒泡” 到数组末尾。 思路&#xff1a; 从数组头开始&#xff0c;比较相邻两个元素。 如果前一个比后一个大&…

Python实现计算点云投影面积

本次我们分享一种基于 Open3D 的快速、稳健方法&#xff0c;用于从激光点云中自动提取“地面”并计算其投影面积。算法先自适应估计地面高程&#xff0c;再将地面点投影至水平面&#xff0c;随后用凸包或最小外接矩形求取面积。整个流程无需人工干预&#xff0c;单文件即可运行…

AXI4 协议

一、AXI4简介AXI4&#xff08;Advanced eXtensible Interface 4&#xff09;是ARM公司推出的高性能片上总线协议&#xff0c;属于AMBA&#xff08;Advanced Microcontroller Bus Architecture&#xff09;标准的一部分。它专为高带宽、低延迟的片上通信设计&#xff0c;广泛应用…

《饿殍:明末千里行》Switch版试玩发布 3月13日发售

使用jQuery的常用方法与返回值分析 jQuery是一个轻量级的JavaScript库&#xff0c;旨在简化HTML文档遍历和操作、事件处理以及动画效果的创建。本文将介绍一些常用的jQuery方法及其返回值&#xff0c;帮助开发者更好地理解和运用这一强大的库。 1. 选择器方法 jQuery提供了多种…

[特殊字符] 认识用户手册用户手册(也称用户指南、产品手册)是通过对产品功能的清

一份优秀的用户手册能有效降低用户的使用门槛&#xff0c;提升用户体验和工作效率。下面我将为你梳理编写用户手册的核心要点、步骤和技巧。&#x1f4d6; 认识用户手册用户手册&#xff08;也称用户指南、产品手册&#xff09;是​​通过对产品功能的清晰解释&#xff0c;为特…

苹果软件代码混淆,iOS混淆、iOS加固、ipa安全与合规取证注意事项(实战指南)

在移动软件交付与合规审计中&#xff0c;苹果软件代码混淆已成为保护知识产权与用户数据的常规手段。但混淆带来的不仅是逆向难度的提升&#xff0c;也会触发崩溃取证、符号化&#xff08;symbolication&#xff09;、审计合规与法律证据保存等问题。本文从工程与合规双视角出发…

Redis框架详解

目录 1. redis是什么 主要特点 2. redis中存储的数据类型 2.1 String类型 2.2 List类型 2.3 Hash类型 2.4 Set类型 2.5 Zset类型 2.6 其它类型 3.redis高可用框架 1. redis是什么 Redis 是一个开源的、基于内存的数据结构存储系统&#xff0c;是 Remote Dictionary…

每日随机展示10个wordpress置顶文章

WordPress 置顶文章是博主根据自己的需要设置的&#xff0c;通常用于展示重要或热门的文章。 以下是一个示例代码&#xff0c;用于在 WordPress 主题中展示 10 个置顶文章&#xff1a; <?php // 查询置顶文章 $sticky get_option(sticky_posts); $args array(post__in …

金融工程vs金融数学:谁更贴近量化交易?

在金融行业迈向高度数字化的今天&#xff0c;量化交易已成为顶尖金融机构的核心竞争力之一。它以数学模型为基础&#xff0c;借助编程技术实现策略自动化&#xff0c;在高频、中低频、套利、因子投资等多个领域展现出强大生命力。对于有志于此的大学生而言&#xff0c;选择一个…