日志搞不定?手把手教你如何使用Log4j2
系列文章目录
从零开始,手把手教你搭建Spring Boot后台工程并说明
Spring框架与SpringBoot的关联与区别
SpringBean生成流程详解 —— 由浅入深(附超精细流程图)
Spring监听器用法与原理详解
Spring事务畅谈 —— 由浅入深彻底弄懂 @Transactional注解
面试热点详解 ——BeanFactory 和 FactoryBean 的关联与区别
忽视日志吃大亏,手把手教你学习Spring Boot日志
日志搞不定?手把手教你如何使用Log4j2
- 系列文章目录
- 一、引入依赖
- 二、配置文件示例
- 三、PatternLayout
- 四、Appenders
- 五、Console
- 1. Filter 过滤器
- 六、RollingFile
- 1. filePattern 文件样板
- 2. Policies 文件原则
- 3. DefaultRolloverStrategy
- 七、Loggers
- 八、异步日志
- 1. 基础使用
- 2. 详细配置
- 总结
上一次我们介绍了Springboot 下的几种常用日志插件,今天我们就专注讲解其中一个最年轻的日志插件,即Log4j2。Log4j2目前应用非常广泛,各方面较之前辈Log4j 都有不小的提升,不过要想利用好他,还得经过一定的学习,尤其是搞清楚它的种种配置,下面就让我们开始今天的进阶之旅。
📕作者简介:战斧,从事金融IT行业,有着多年一线开发、架构经验;爱好广泛,乐于分享,致力于创作更多高质量内容
📗本文收录于 Spring全家桶 专栏,有需要者,可直接订阅专栏实时获取更新
📘高质量专栏 云原生、RabbitMQ、Spring全家桶 等仍在更新,欢迎指导
📙Zookeeper Redis kafka docker netty等诸多框架,以及架构与分布式专题即将上线,敬请期待
一、引入依赖
我们可以使用以下依赖为我们项目引入Log4j2框架
<!--Log4j2自带的日志门面-->
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.13.3</version>
</dependency>
<!--Log4j2具体的日志实现-->
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.13.3</version>
</dependency>
当然,像上期所说,我更建议直接使用以下log4j-slf4j-impl
包
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.13.3</version>
</dependency>
该包包含Log4j2的实现,也能对接SLF4J,更适合在项目中应用。
二、配置文件示例
我们看如下一份配置文件:log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG" monitorInterval="30"><!-- 输出格式 --><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} - [%t] %-5level %logger{36} - %msg%n"/><Appenders><!-- 控制台输出 --><Console name="Console" target="SYSTEM_OUT"><!-- 过滤器 --><ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/><!-- 缓冲bufferSize,默认值为256,可调整至1-256之间 --><Buffered mode="ONCE" bufferSize="256"/></Console><!-- 文件输出 --><RollingFile name="RollingFile" fileName="/path/to/logs/test.log" filePattern="/path/to/logs/$${date:yyyy-MM}/test-%d{yyyy-MM-dd}-%i.log"><ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/><!-- 输出格式 --><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/><!-- 触发策略 --><Policies><!-- 按时间滚动 --><TimeBasedTriggeringPolicy/><!-- 按文件大小滚动,这里设置10MB --><SizeBasedTriggeringPolicy size="10MB"/></Policies><!-- 滚动策略 --><DefaultRolloverStrategy max="10"/></RollingFile></Appenders><Loggers><!-- 默认日志 --><Root level="INFO"><AppenderRef ref="Console"/><AppenderRef ref="RollingFile"/></Root><!-- 指定包名的日志 --><Logger name="com.example" level="DEBUG" additivity="false"><AppenderRef ref="Console"/><AppenderRef ref="RollingFile"/></Logger></Loggers>
</Configuration>
三、PatternLayout
PatternLayout
是一种日志输出格式,用于设置日志输出的布局格式。该格式使用一系列特定的占位符,每个占位符都代表一种日志信息,例如输出日志事件的时间、线程名、日志级别、日志内容等
- %d:输出日志事件的时间戳
- %t:输出线程名
- %-5level:输出日志级别,包括5个字符位置(例如,DEBUG、INFO、WARN、ERROR、FATAL),将小于5个字符的级别左对齐
- %logger{36}:输出日志记录器的名称,最多36个字符
- %msg:输出日志内容
- %n:输出平台相关的行分隔符
- %M:输出产生日志事件的方法名
- %L:输出语句在源文件中出现的行号
- %l:输出语句的精确位置,包含类、方法和行号
- %c:输出日志事件相关的类名
我们举两个例子,假如我们配置文件这么写
<PatternLayout pattern="%d{ISO8601} [%t] %-5level %logger{36} - %msg%n" />
输出的结果就为
2023-08-23T19:34:26,068 [main] INFO com.zhanfu.Main - This is a Main info message.
如果配置文件如下
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} |-%-5level [%t] %c{1.} %M [%L] -| %msg%n"/>
输出的结果就为
2023-08-23 20:18:06.833 |-INFO [main] c.z.Main main [11] -| This is a Main info message.
其中,%c{1.}
表示输出日志事件相关的类名,只取最右边的类名,前面的层级,只输出一个字母;如果配置文件如下
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} |-%-5level [%t] %c{2.} [%l] -| %msg%n"/>
输出的结果就为
2023-08-23 20:21:00.753 |-INFO [main] co.zh.Main [com.zhanfu.Main.main(Main.java:11)] -| This is a Main info message.
四、Appenders
Appenders
是指日志输出的目的地。它定义了日志事件要被输出到哪些地方,例如控制台、文件、数据库等,其下可以配置不同类型的Appender
,我们罗列其中常见的一些:
- Console:向控制台输出日志。
- File:将日志记录到文件中。
- RollingFile:将日志记录到指定大小的文件中,并支持文件滚动。
- Socket:将日志发送到远程 Socket 服务器
- Kafka:将日志发送到 Kafka 消息队列。
- Redis:将日志发送到 Redis 服务器。
- Jdbc:将日志记录到数据库中
对于单机应用来说,Console
与 File
是最为常用的,但对于集群,通常需要进行日志采集,此时也会通过Socket
或Kafka
等将日志发送至其他位置
五、Console
Console
标签是用于将日志输出到控制台的标签,其有以下可配置的属性:
- name:配置Console标签的名称。
- target:配置Console标签输出的目标,可以是System.out或System.err,默认为System.out。
- follow:配置Console标签,控制台是否跟随日志进行滚动,默认为false。
- immediateFlush:配置Console标签的输出是否立即刷新,默认为true
Console
标签可以包含以下子标签
- PatternLayout:上文已经介绍过,可以自定义输出的格式。此标签有以下可配置的属性:pattern。
- ThresholdFilter:指定哪些日志级别应该被输出或被拒绝。此标签有以下可配置的属性:
- level - 匹配的可用的日志级别。
- onMatch - 当匹配或高于指定日志等级时的动作,可以为 ACCEPT、DENY、NEUTRAL 之一,默认为 NEUTRAL
- onMismatch - 当低于指定日志等级时的动作,可以为 ACCEPT、DENY、NEUTRAL ,默认为 DENY
- RegexFilter:使用正则表达式来计算哪些日志消息应该被过滤。
1. Filter 过滤器
比如我们可以做出如下配置
<Console name="console" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/><ThresholdFilter level="WARN" onMatch="NEUTRAL " onMismatch="DENY"/><RegexFilter regex=".*\[(main|AsyncLogger)\].*"/>
</Console>
我们可以发现 ThresholdFilter
的设置为 level=“WARN” onMatch="NEUTRAL " onMismatch=“DENY”,这种设置的意思就是当日志等级高于或等于 WARN
时,就通过了级别过滤器,但还需要经过后续过滤器如的进一步筛选。而低于 WARN
则直接拒绝打印。
比如我们有这样的过滤设置
<ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<ThresholdFilter level="warn" onMatch="DENY" onMismatch="DENY"/>
第一个过滤器否决打印error级别,第二个过滤器接收大于info级别,并且否决低于info级别的,那最终只能打印info 和 warn 级别了。此处的第三个过滤器实际上没被用到
六、RollingFile
RollingFile
标签用于配置滚动日志输出到文件的方式,什么叫滚动日志,就是日志输出在一个文件中,当某个事件发生时(如文件达到一定大小),会把这个文件进行归档封存,然后新建一个文件,再向新建的文件中输出日志,有点像现代的饮料生产线,灌满一瓶立即灌下一瓶
以下是RollingFile标签的常用属性:
- name:指定RollingFile的名称,用于标识该Appender。
- fileName:指定日志文件的路径和名称。
- filePattern:指定日志文件备份的命名模式,使用%符号指定日期、数字等占位符。
RollingFile
可以包含下列子标签
- policies:指定日志滚动策略,包括时间、大小等,可以使用TimeBasedTriggeringPolicy、SizeBasedTriggeringPolicy等标签。
- PatternLayout:指定日志输出格式,上面已经说过。
我们可以以下面的配置为例子进行进一步解释
<Appenders><RollingFile name="RollingFile"fileName="/logs/app.log"filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log"><PatternLayout><pattern>%d %p %c{1.} [%t] %m%n</pattern></PatternLayout><Policies><TimeBasedTriggeringPolicy interval="1" modulate="true"/><SizeBasedTriggeringPolicy size="10 MB"/></Policies><DefaultRolloverStrategy max="5"/></RollingFile>
</Appenders>
该示例配置了一个名为“RollingFile”的RollingFile Appender,将日志记录到“/logs/app.log”文件中。文件名模式为“/logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz”
1. filePattern 文件样板
filePattern
是RollingFile Appender的一个属性,用于指定根据何种模式生成归档滚动日志文件的名称。filePattern可以使用一些特定的占位符,以便在滚动时自动生成新的日志文件名
filePattern占位符:
- %d - 日期格式化器的格式化日期。例如:2018-09-19
- %i - 滚动文件的索引编号,从1开始。
- %n - 系统的行分隔符
- %m - 文件名
比如我们设置的
filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log"
filePattern中的时间占位符%d在滚动时会自动更新为当前时间,索引号%i也会自动递增以避免覆盖先前的日志,所以最终会生成以下的归档文件名
app-2021-08-30-15-1.log
app-2021-08-30-15-2.log
app-2021-08-30-15-3.log
2. Policies 文件原则
Policies
用于定义何时触发滚动动作以生成新的日志文件,可以定义TimeBased和SizeBased两种类型的触发策略。
-
TimeBasedTriggeringPolicy
TimeBasedTriggeringPolicy
是基于时间的触发策略,当指定的时间间隔过去时,将会触发滚动动作。
属性:- interval:时间间隔,单位为filePattern中的最小时间单位,如%d{yyyy-MM-dd-HH}代表最小时间为小时,默认数值为1。
- modulate:是否调节,即使用0时0分作为起点,当开启时,下一次生成日志文件的时间为0时0分 + n 个interval
-
SizeBasedTriggeringPolicy
SizeBasedTriggeringPolicy
是基于日志文件大小的触发策略,当日志文件大小达到指定的大小时,将会触发滚动动作
属性:
-size:指定的日志文件大小,单位为字节,默认值为10MB
需要注意的是,
1.若modulate=true, 则封存时间将以0点为边界进行偏移计算。比如,modulate=true,interval=4hours,那么假设上次封存日志的时间为03:00,则下次封存日志的时间为04:00,之后的封存时间依次为08:00,12:00,16:00…如果modulate=false,则代表不调整,封存时间严格遵循离上次间隔4小时,则封存时间依次为07:00,11:00,15:00…
2.Policies可以同时指定多个触发策略,从而满足多种情况下的滚动需求,例如
<RollingFile name="example"fileName="logs/logfile.log"filePattern="logs/logfile-%d{yyyy-MM-dd_HH}.log"><Policies><TimeBasedTriggeringPolicy interval="5" modulate="true"/><SizeBasedTriggeringPolicy size="100 MB"/></Policies><DefaultRolloverStrategy max="5"/>
</RollingFile>
以上配置将在每隔五小时或100M时将生成一个新的日志文件,文件名会包含时间戳
3. DefaultRolloverStrategy
DefaultRolloverStrategy
是一个滚动策略,可以设置滚动文件数量以及删除策略,它有以下几个属性:
- max:最大日志文件数量,默认为7。
- min:最小日志文件数量,默认为1。
- fileIndex:日志文件序号的格式,默认为%s。
- compressionLevel:压缩级别,默认为6
同时,它也支持以下子标签:
- Delete:用于配置何时删除过期的日志文件。
- CustomDelete:用于自定义删除过期日志文件的行为。
比如以下设置
<DefaultRolloverStrategy max="10" min="2" fileIndex="max"><Delete basePath="logs" maxDepth="2"><IfFileName glob="*.log" /><IfLastModified age="14d" /></Delete>
</DefaultRolloverStrategy>
这代表日志文件最多保留10个,最少保留2个,日志文件序号格式为max,同时配置了Delete子标签,用于删除14天前的logs文件夹下,两层路径以内的所有.log文件。其中,Delete子标签中的IfFileName和IfLastModified子标签用于指定删除条件,只有同时满足两个条件才进行删除操作
需要注意的是,文件的多少与我们设置的 filePattern 也有关系,其限制的其实是%i的最大数值:
比如
filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log
这代表文件归档最小单位为小时,如果我们的 DefaultRolloverStrategy max="10" ,那么一个小时内最多保留10个文件,
当产生第11个文件时,将会删除本小时最早的日志文件
七、Loggers
Loggers
和Logger
标签是用来配置日志记录器的。Loggers标签是定义所有Logger的容器标签,而Logger标签则是具体的记录器配置,Logger 标签有以下属性:
- name:指定Logger的名称,名称可以是类名、包名或自定义的名称。例如,如果设置为com.example.MyLogger,则日志内容将包含该名称。
- level:指定Logger的日志级别,如果不指定则将继承Loggers标签中的默认级别。例如,如果设置为INFO,则只会记录INFO及以上级别的日志。
- additivity:指定Logger是否继承它的父Logger的Appender。如果不指定,则将继承Loggers标签中的默认值。
- includeLocation:指定是否包含日志输出的调用位置信息。如果设置为true,则输出的日志将包括文件名、方法名和行号等信息。
- suppressExceptions:指定是否屏蔽日志输出中的异常信息。如果设置为false,则将在日志输出中包含异常信息
Logger标签还包括AppenderRef
子标签,用于指定Logger所要使用的Appender。可以在Logger标签中指定多个AppenderRef,这样就可以将同一个Logger的日志输出到多个Appender中
下面是一个典型的Loggers与Logger的例子:
<Appenders><RollingFile name="MyAppender"fileName="/logs/app.log"filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log"><PatternLayout><pattern>%d %p %c{1.} [%t] %m%n</pattern></PatternLayout><Policies><TimeBasedTriggeringPolicy interval="1" modulate="true"/><SizeBasedTriggeringPolicy size="10 MB"/></Policies><DefaultRolloverStrategy max="5"/></RollingFile><Console name="Console" target="SYSTEM_OUT"><ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/><Buffered mode="ONCE" bufferSize="256"/></Console>
</Appenders>
<Loggers><Logger name="com.example.MyLogger" level="info"><AppenderRef ref="MyAppender"/></Logger><Root level="error"><AppenderRef ref="Console"/></Root>
</Loggers>
这个例子中定义了两个Logger
:com.example.MyLogger和Root
。com.example.MyLogger的级别是INFO,只会记录INFO及以上级别的日志,并且使用MyAppender作为输出目的地;Root的级别是ERROR,将所有ERROR及以上级别的日志输出到Console中
八、异步日志
1. 基础使用
我们上面讲解的其实都是同步输出的日志,而Log4j2 的一大特性就是其异步输出能力,我们可以参考如下配置
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"><Appenders><File name="File" fileName="logs/app.log"><PatternLayout><Pattern>%d %p %C{1.} [%t] %m%n</Pattern></PatternLayout></File><Async name="Async"><AppenderRef ref="File"/></Async></Appenders><Loggers><Logger name="com.example" level="debug"/><Root level="info"><AppenderRef ref="Async"/></Root></Loggers>
</Configuration>
- 首先,定义了一个文件输出的Appender,文件名为logs/app.log,并且在PatternLayout中指定了日志输出的格式。
- 接着,定义了一个异步的Appender,它的AppenderRef指向了文件输出的Appender。
- 最后,将Root Logger的级别设为info,并让它的AppenderRef指向了异步的Appender。
这个配置可以实现将日志异步输出到logs/app.log文件中,并且可以指定日志输出的格式
我们可以做一个测试,分别用同步和异步的方式进行运行:
public static void main(String[] args) {long startTime = System.currentTimeMillis();for (int i = 0; i < 1000000; i++) {log.info("This is a debug message. Count is "+i);}long endTime = System.currentTimeMillis();log.info("Total time: "+(endTime - startTime)+"ms");}
可以看到,异步确实能节约很多时间。
2. 详细配置
我们注意到最后一个阻塞队列的信息,其实不难想象,这里的日志异步依赖的就是高性能队列,不仅log4j2
,像Netty
等对性能有极高要求的框架,在队列的选择上都是精益求精的。log4j2支持四种阻塞队列,如下:
比如我们如果想指定一种阻塞队列,可以这么设置:
<Configuration name="LinkedTransferQueueExample"><Appenders><List name="List"/><Async name="Async" bufferSize="262144"><AppenderRef ref="List"/><AsyncQueueFullPolicy type="Discard"/><!-- 指定阻塞队列 --><LinkedTransferQueue/></Async></Appenders><Loggers><Root><AppenderRef ref="Async"/></Root></Loggers>
</Configuration>
当然,如果你想使用 DisruptorBlockingQueue
,那还需要引入 disruptor 包,注意版本兼容,log4j-2.17.1 对应了disruptor-3.4.0
<dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.0</version>
</dependency>
总结
本次我们比较详细的介绍了Log4j2框架的种种配置,虽然没有讲原理,但解释了不少配置并给出示例,相信即便是新手,阅读完也能应对大部分使用场景了。希望大家能够举一反三,灵活运用。当然,有问题也可以直接去官方文档进行查阅和学习,点此直达
log4j2 手册
相关文章:
日志搞不定?手把手教你如何使用Log4j2
系列文章目录 从零开始,手把手教你搭建Spring Boot后台工程并说明 Spring框架与SpringBoot的关联与区别 SpringBean生成流程详解 —— 由浅入深(附超精细流程图) Spring监听器用法与原理详解 Spring事务畅谈 —— 由浅入深彻底弄懂 Transactional注解 面试热点详解…...
基于Googlenet深度学习网络的交通工具种类识别matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ....................................................................................% 获…...
R语言04-R语言中的列表
概念 在R语言中,列表(List)是一种复杂的数据结构,用于存储不同类型的元素,包括向量、矩阵、数据框、函数等。列表是一种非常灵活的数据结构,可以将不同类型的数据组合在一起,类似于Python中的字…...
[Linux]进程概念
[Linux]进程概念 文章目录 [Linux]进程概念进程的定义进程和程序的关系Linux下查看进程Linux下通过系统调用获取进程标示符Linux下通过系统调用创建进程-fork函数使用 进程的定义 进程是程序的一个执行实例,是担当分配系统资源(CPU时间,内存…...
GEE/PIE遥感大数据处理与应用
随着航空、航天、近地空间等多个遥感平台的不断发展,近年来遥感技术突飞猛进。由此,遥感数据的空间、时间、光谱分辨率不断提高,数据量也大幅增长,使其越来越具有大数据特征。对于相关研究而言,遥感大数据的出现为其提…...
● 647. 回文子串 ● 516.最长回文子序列
647. 回文子串 class Solution { public:int countSubstrings(string s) {vector<vector<bool>>dp(s.size(),vector<bool>(s.size(),false));int res0;for(int is.size()-1;i>0;i--){for(int ji;j<s.size();j){if(s[i]s[j]){if(j-i<1){res;dp[i][…...
Mysql group by使用示例
文章目录 1. groupby时不能查询*2. 查询出的列必须在group by的条件列中3. group by多个字段,这些字段都有索引也会索引失效,只有group by单个字段索引才能起作用4. having条件必须跟group by相关联5. 用group by做去重6. 使用聚合函数做数量统计7. havi…...
淘宝商品详情采集接口item_get-获得淘宝商品详情(可高并发线程)
获得淘宝商品详情页面数据采集如下: taobao.item_get 公共参数 名称类型必须描述keyString是调用key(必须以GET方式拼接在URL中)注册key账号接入secretString是调用密钥api_nameString是API接口名称(包括在请求地址中࿰…...
uniapp写公众号h5开发 附件上传 下载功能
一。 uni-app实现文件上传功能 目前,找到一款第三方插件 文件上传插件地址 https://ext.dcloud.net.cn/plugin?id=1015 将插件下载并导入项目中直接拿来使用,插件市场也有对改插件用法的描述。 用法: 1. 以下代码写于根目录下第一个view顶部或跟在自定义导航栏后面 // 以…...
机器学习基础09-审查分类算法(基于印第安糖尿病Pima Indians数据集)
算法审查是选择合适的机器学习算法的主要方法之一。审查算法前并 不知道哪个算法对问题最有效,必须设计一定的实验进行验证,以找到对问题最有效的算法。本章将学习通过 scikit-learn来审查六种机器学习的分类算法,通过比较算法评估矩阵的结果…...
C++ sort与优先队列排序的区别
int main() {vector<int> data{3, 1, 2};cout << "从小到大排序" << endl;sort(data.begin(), data.end(), std::less<int>());printContainer(data);auto cmp1 [](int x, int y) { return x < y; };sort(data.begin(), data.end(), cmp…...
【Rust】Rust学习 第十九章高级特征
现在我们已经学习了 Rust 编程语言中最常用的部分。在第二十章开始另一个新项目之前,让我们聊聊一些总有一天你会遇上的部分内容。你可以将本章作为不经意间遇到未知的内容时的参考。本章将要学习的功能在一些非常特定的场景下很有用处。虽然很少会碰到它们…...
C++ 纯虚函数和虚函数的区别
在 C 中,虚函数(Virtual Function)和纯虚函数(Pure Virtual Function)都是用于实现多态性的机制,但它们之间有一些关键的不同。 虚函数(Virtual Function) 定义:在基类…...
Go中的有限状态机FSM的详细介绍 _
1、FSM简介 1.1 有限状态机的定义 有限状态机(Finite State Machine,FSM)是一种数学模型,用于描述系统在不同状态下的行为和转移条件。 状态机有三个组成部分:状态(State)、事件(…...
Python入门教程 | Python3 基本数据类型
赋值 Python 中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。 在 Python 中,变量就是变量,它没有类型,我们所说的"类型"是变量所指的内存中对象的类型。 等号(ÿ…...
STM32移植u8g2玩转oled 用软件iic实现驱动oled
移植u8g2到stm int fputc(int ch,FILE *f) {ITM_SendChar(ch);return (ch); }void delay_us(uint32_t time) {uint32_t i8*time;while(i--); }uint8_t STM32_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {//printf("%s:msg %d,arg_int …...
C++ 学习系列 -- string 实现
string是C标准库的重要部分,主要用于字符串处理。这里我们自己实现一个简单版本的 string. 一 思路 string 类中应该包含如下: 1. 类成员变量:char* m_data,利用 char* 指针存放字符串 2. 成员函数: 2.1 size(…...
C语言小练习(三)
🌞 “也许你感觉自己与周遭格格不入,但正是那些你一人度过的时光,让你变得越来越有意思,等有天别人终于注意到你的时候,他们就会发现一个比他们想象中更酷的人。”-《生活大爆炸》 Day03 📝 一.选择题&…...
2023 js逆向爬虫 有道翻译 代码
前置条件:nodejs环境、安装 crypto 和 python3环境 js.js文件: const crypto require("crypto")function decode(resp_data) {g_o ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHlg_n ydsecre…...
【物联网无线通信技术】NFC从理论到实践(FM17XX)
NFC,全称是Near Field Communication,即“近场通信”,也叫“近距离无线通信”。NFC诞生于2004年,是基于RFID非接触式射频识别技术演变而来,由当时的龙头企业NXP(原飞利浦半导体)、诺基亚以及索尼联合发起。NFC采用13.5…...
Python爬虫猿人学逆向系列——第六题
题目:采集全部5页的彩票数据,计算全部中奖的总金额(包含一、二、三等奖) 地址:https://match.yuanrenxue.cn/match/6 本题比较简单,只是容易踩坑。话不多说请看分析。 两个参数,一个m一个f&…...
idea使用tomcat
1. 建立javaweb项目 2. /WEB-INF/web.xml项目配置文件 如果javaweb项目 先建立项目,然后在项目上添加框架支持,选择javaee 3. 项目结构 4.执行测试:...
搭建Tomcat HTTP服务:在Windows上实现外网远程访问的详细配置与设置教程
文章目录 前言1.本地Tomcat网页搭建1.1 Tomcat安装1.2 配置环境变量1.3 环境配置1.4 Tomcat运行测试1.5 Cpolar安装和注册 2.本地网页发布2.1.Cpolar云端设置2.2 Cpolar本地设置 3.公网访问测试4.结语 前言 Tomcat作为一个轻量级的服务器,不仅名字很有趣࿰…...
Java学习笔记——继承(包括this,super的使用总结)
继承: 使用情景:当类与类之间,存在相同(共性)的内容,并满足子类是父类的一种,就可以考虑使用继承,来优化代码 Java中提供一个关键字extends,用这个关键字,我…...
Android 获取应用sha1和sha256
在 Android 应用开发中,SHA-1(Secure Hash Algorithm 1)值是一种哈希算法,常用于生成应用的数字签名。这个数字签名用于验证应用的身份,并确保应用在发布到设备上时没有被篡改。 以下是生成 Android 应用的 SHA-1 值的…...
c# 方法参数修饰符(out、ref、in)的区别
在C#中,ref、out和in是三种方法参数修饰符,它们在传递参数的方式和作用上有所不同。 ref修饰符: 传递方式:使用ref修饰符的参数可以是输入输出参数,即在方法调用前后都可以对其进行修改。 作用:通过ref修…...
shell 编写一个带有进度条的程序安装脚本
需求 使用 shell 写一个 软件安装脚本,带有进度条 示例 #!/bin/bash# 模拟软件安装的步骤列表 steps("解压文件" "安装依赖" "配置设置" "复制文件" "")# 计算总步骤数 total_steps${#steps[]}# 安装进度的初…...
服务器数据恢复-AIX PV完整镜像方法以及误删LV的数据恢复方案
AIX中的PV相当于物理磁盘(针对于存储来说,PV相当于存储映射过来的卷;针对操作系统来说,PV相当于物理硬盘),若干个PV组成一个VG,AIX可以将容量不同的存储空间组合起来统一分配。AIX把同一个VG的所…...
首席执行官Adam Selipsky解读“亚马逊云科技的技术产品差异化”
迄今为止,亚马逊云科技已经参与了21世纪几乎所有的大型计算变革,亚马逊云科技是一个很传奇的故事,它始于大约20年前的一项实验,当时亚马逊试图出售其过剩的服务器。人们确实对此表示怀疑。为什么在线书店试图销售云服务࿱…...
C++ Day3
目录 一、类 【1】类 【2】应用实例 练习: 【3】封装 二、this指针 【1】this指针的格式 【2】必须使用this指针的场合 三、类中的特殊成员函数 【1】构造函数 i)功能 ii)格式 iii)构造函数的调用时机 iv)…...
建设网站所需技术/常用网站推广方法及资源
O/R mapping 对象关系映射 把数据库,sql语言f封装成对象,让我们的编程更加对象化 这就是好处 第一步,建立hibernate用户库 第二步,建立实体类student package com.bjsxt.hibernate;public class Student {private int id;…...
公司网站建设手续/万网域名查询官网
ipython的安装 ipython可以直接使用pip install ipython安装 ,如果安装失败按如下步骤手动进行安装 所需文件下载: 链接:http://pan.baidu.com/s/1dE756OL 密码:rlzh ipython是一个 python 的交互式 shell,比默认的python shell好…...
政府平台网站建设建议/自己如何制作网页
C,libpq - C 库,ECPG - C 中的嵌入式 SQL C,把 C 用于可扩展性 canceling,取消进行中的查询 SQL command,取消进行中的查询 cardinality,数组函数和操作符 CASCADE,依赖跟踪 with DROP&am…...
手机维修网站那个公司做的/深圳推广
先并查集,然后最小生成树,最短路,强连通,双连通,LCA,二分匹配,网络流,2-sat 这部分搞完后,开始树直径,树重心,欧拉回路,树分治 转载于…...
成都网站建设优创/锦州seo推广
这个案例是官方案例,个人通过一个一个测试备注,感受模型如何配置参数,来生成理想的形状。three.js内置的这些几何确实够平常使用,还可以通过顶点实现效果。 案例查看地址:http://www.wjceo.com/blog/threejs/2018-02-0…...
手机零售网站 关键词/seo比较好的公司
1、Flume定义 Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统。Flume基于流式架构,灵活简单。 说白了就是收集日志的小组件。采集日志的单位是一行一行的。MapReduce不是流式架构的,Spark…...