c++日志工具之——log4cpp
1、log4cpp概述
Log4cpp是一个开源的C++类库,它提供了C++程序中使用日志和跟踪调试的功能,它的优点如下:
-
提供应用程序运行上下文,方便跟踪调试;
-
可扩展的、多种方式记录日志,包括命令行、文件、回卷文件、内存、syslog服务器、Win事件日志等;
-
可以动态控制日志记录级别,在效率和功能中进行调整;
-
所有配置可以通过配置文件进行动态调整;
-
多语言支持,包括Java(log4j),C++(log4cpp、log4cplus),C(log4c),python(log4p)等;
类似日志工具:glog、boost.log、spdlog
2、原理
Log4cpp有三个主要的组件:日志类别(Category)、输出源(Appender)和布局(Layout)。这三种类型的组件一起工作使得系统可以根据信息的类型和级别记录它们,并且在运行时控制这些信息的输出格式和位置。
三个组件的介绍:
1)日志类别(Category)含义是:如果配置文件中设置的级别是DEBUG,则任意的log都能打印出来;但如果配置的级别是ERROR,则只有高于ERROR优先级的日志才可以打印出来。
日志的常用优先级:DEBUG < INFO < WARN < ERROR < FATAL
2)输出源(Appender)用来输出日志(被layout格式化后)到一些设备上,比如文件、命令行、内存等。也可以定义自己的appender输出日志信息到别的设备上。log4cpp提供的appender如下: FileAppender 输出到文件 RollingFileAppender 输出到回卷文件,即当文件到达某个大小后回卷 ConsoleAppender 输出到控制台
3)布局(Layout):显示样式PatternLayout表示让用户根据类似于C语言printf函数的转换模式来指定输出格式
三个组件之间的关系:
-
Category和Appender的关系是:多个Appender可以附加到一个Category上,这样一个日志消息可以同时输出到多个设备上。
-
Appender和Layout的关系是:Layout附加在Appender上,appender调用layout处理完日志消息后,记录到某个设备上。
3 log4cplus的安装
log4cplus是开源的,源代码可在这里找到。下载源代码压缩包后解压,进入主目录。和大多数autotools工程一样,顺序执行以下命令即可完成安装。
./configure
make
make install
安装文件将默认安装到/usr/local,库文件置于/usr/local/lib,头文件置于/usr/local/include。
是的,这里介绍的安装及下面介绍的应用都是基于linux系统。
4 log4cplus的使用
以下是官方提供的“hello, world”的示例程序:
#include <log4cplus/logger.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/configurator.h>
#include <iomanip>using namespace log4cplus;int main()
{BasicConfigurator config;config.configure();Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("main"));LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT("Hello, World!"));return 0;
}
程序包含了一些必要的头文件,编译时需要链接log4cplus库,将这段代码保存为 test.cpp,执行以下命令编译:
g++ test.cpp -o test -llog4cplus
编译后生成 test 可执行文件,运行./test,得到如下输出:
WARN - Hello, World!
这个程序使用的是log4cplus内置的默认配置选项,实际使用中一般要自己配置选项,接下来你会看到。
相关视频推荐
如何设计高效日志库
C++ Golang日志库Glog源码分析
c++后端绕不开的7个开源项目,每一个源码值得深入研究
免费学习地址:c/c++ linux服务器开发/后台架构师
需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
5 log4cplus配置
log4cplus配置就是定义appender, 定义输出的格式即 layout。以下列出两种常用配置,以供参考。
配置输出到控制台(通常用于前台程序):
log4cplus.logger.logmain = TRACE, console
log4cplus.appender.console = log4cplus::ConsoleAppender
log4cplus.appender.console.layout = log4cplus::PatternLayout
log4cplus.appender.console.layout.ConversionPattern = [%D{%m/%d/%y %H:%M:%S,%q} %-5p] - %m%n
配置输出到文件(通常用于后台程序):
log4cplus.logger.logmain = INFO, file
log4cplus.appender.file = log4cplus::FileAppender
log4cplus.appender.file.File = /var/log/myapp.log
log4cplus.appender.file.MaxFileSize = 10M
log4cplus.appender.file.Append = true
log4cplus.appender.file.layout = log4cplus::PatternLayout
log4cplus.appender.file.layout.ConversionPattern = [%D{%m/%d/%y %H:%M:%S,%q} %-5p] - %m%n
简单说明一下,配置文件中log4cplus.logger.logmain即定义一个logmain对象,后面跟的两个字段前一个表示log级别,后一个指定使用的appender,即日志输出对象。log级别按严重程度从低到高依次为TRACE、DEBUG、INFO、WARN、ERROR、FATAL。log4cplus.appender.xxx定义具体的appender属性,如是控制台还是文件,进一步配置文件名、文件大小等。
将配置保存到一个配置文件中(如log4cplus.conf),以下你将看到如何使用配置文件。有关更详细的配置,读者可自行摸索。
6 log4cplus运用于项目
以上“hello, world”程序只是大概演示log4cplus的用法,实际项目使用要有系统观念,就是怎样用才更方便,我们可以再做点封装。我们可以定义一个全局logger对象,将log4cplus初始化配置放到一个源文件中,重新定义一些简化的宏置于头文件,比如笔者就定义了Log.h/Log.cpp两个文件,代码如下:
Log.h文件:
#pragma once#include <log4cplus/logger.h>
#include <log4cplus/loggingmacros.h>using namespace log4cplus;
using namespace log4cplus::helpers;// global object
extern Logger logger;// define some macros for simplicity
#define LOG_TRACE(logEvent) LOG4CPLUS_TRACE(logger, logEvent)
#define LOG_DEBUG(logEvent) LOG4CPLUS_DEBUG(logger, logEvent)
#define LOG_INFO(logEvent) LOG4CPLUS_INFO(logger, logEvent)
#define LOG_WARN(logEvent) LOG4CPLUS_WARN(logger, logEvent)
#define LOG_ERROR(logEvent) LOG4CPLUS_ERROR(logger, logEvent)
#define LOG_FATAL(logEvent) LOG4CPLUS_FATAL(logger, logEvent)extern void InitLogger(bool daemonized);
Log.cpp文件:
#include <log4cplus/logger.h>
#include <log4cplus/consoleappender.h>
#include <log4cplus/fileappender.h>
#include <log4cplus/layout.h>
#include <log4cplus/configurator.h>#include "Log.h"Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("logmain"));void InitLogger(bool daemonized)
{if (daemonized)PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("/your/path/log4cplusd.conf"));elsePropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("/your/path/log4cplus.conf"));
}
将这两个文件置于你的项目中,然后在 main 函数中调用 InitLogger() 初始化 log4cplus,再在需要加log的文件中包含Log.h即可。注意InitLogger函数的参数daemonized,该参数表示应用程序是否是守护进程(后台运行),一般我们开发的应用程序大多是守护进程(linux后台服务大多是守护进程),但调试的时候会前台运行,对于守护进程,我们只需要把日志记录到某个文件中就行了,而对于前台调试运行,我们就只需要将日志输出到控制台,所以这里是一点使用技巧。做到这点我们只需分别提供两个配置文件即可,"/your/path"就是你放置配置文件的地方,一般可以设为你应用程序部署的目录下的etc目录。
至此我们可以使用log4cplus了!以下是实际的日志输出效果:
[11/05/12 10:28:36,002 INFO ] - TCPDomain - TCPDomain()
[11/05/12 10:28:36,002 INFO ] - TCPDomain - Connect server success!
[11/05/12 10:28:36,002 TRACE] - Session - Thread run.
[11/05/12 10:28:46,006 ERROR] - TCPDomain - SelectRead time out!
[11/05/12 10:28:56,016 ERROR] - TCPDomain - SelectRead time out!
7 log4cplus交叉编译
对于嵌入式应用 ,有交叉编译这么一说。以上的介绍是基于PC的,如果你的平台是嵌入式平台如arm,则只需编译链接arm平台的log4cplus库即可,其它都一样。对于大多数autotools工程,其交叉编译方法大致如下:
./configure --prefix=/your/install/path --host=arm-linux CXX=your-toolkit-g++
make
make install
其中--prefix即指定你的安装目录,如/opt/log4cplus,--host指定目标平台,CXX指定你的交叉编译工具(确保shell环境能找到该工具)。编译安装完后可在安装目录找到arm版本的库文件。
8 总结
日志固然好,但也不建议随意使用,用多了会导致程序性能有所下降,且代码size增加不少。以上是笔者运用log4cplus的些许经验,更深一步的原理机制有待进一步探究。
配置文件
1 #-------定义rootCategory的属性-------2 3 #指定rootCategory的log优先级是ERROR,其Appenders有两个,分别是console,TESTAppender4 log4cpp.rootCategory=ERROR, console,TESTAppender5 6 #-------定义console属性-------7 8 #consoleAppender类型:控制台输出9 #下面这三条语句表示控制台输出的log输出的布局按照指定的格式;输出格式是:[%p] %d{%H:%M:%S.%l} (%c): %m%n
10 log4cpp.appender.console=ConsoleAppender
11 log4cpp.appender.console.layout=PatternLayout
12 log4cpp.appender.console.layout.ConversionPattern=[%p] %d{%H:%M:%S.%l} (%c): %m%n
13
14 #-------定义TESTAppender的属性-------
15
16 #RollingFileAppender类型:输出到回卷文件,即文件到达某个大小的时候产生一个新的文件
17 #下面的语句表示文件输出到指定的log文件,输出的布局按照指定的格式,输出的格式是:[%d{%Y-%m-%d %H:%M:%S.%l} - %p] (%c): %m%n
18 log4cpp.appender.TESTAppender=RollingFileAppender
19
20 #当日志文件到达maxFileSize大小时,将会自动滚动
21 log4cpp.appender.TESTAppender.maxFileSize=400000
22
23 #maxBackupIndex指定可以产生的滚动文件的最大数
24 log4cpp.appender.TESTAppender.maxBackupIndex=3
25
26 #fileName指定信息输出到logs/TESTAppender.txt文件
27 log4cpp.appender.TESTAppender.fileName=logs/TESTAppender.txt
28
29 #PatternLayout 表示可以灵活指定布局模式
30 log4cpp.appender.TESTAppender.layout=PatternLayout
31
32 #append=true 信息追加到上面指定的日志文件中,false表示将信息覆盖指定文件内容
33 log4cpp.appender.TESTAppender.append=true
34 log4cpp.appender.TESTAppender.layout.ConversionPattern=[%d{%Y-%m-%d %H:%M:%S.%l} - %p] (%c): %m%n ConversionPattern的参数含义:%d 输出日志时间点的日期或时间,可以在其后指定格式,如上%d{%Y-%m-%d %H:%M:%S.%l},输出类似:2017-02-14 09:25:00.953
%p 优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%c 输出日志信息所属的类目,通常就是所在类的全名
%m 输出log的具体信息
%n 回车换行
自定义封装
将上述过程封装,即可得到自己的日志类
/*采用单例模式设计,包含两个category对象,一个负责输出到屏幕的信息,一个负责记录到日志的信息,通过设置优先级差别,可以实现所有信息都记录在日志中,遇到error及以上的信息时打印到屏幕上*/
class MyLog
{
private:MyLog(bool b){outToScreen = b;}~MyLog(){}static MyLog * log;bool outToScreen;//是否输出日志信息到屏幕static std::string _screenInfo;//屏幕日志信息static std::string _logName;//文件日志名称static log4cpp::Category& logCat;static log4cpp::Category& coutCat;static log4cpp::FileAppender* logFile;//文件日志输入static log4cpp::OstreamAppender* logScreen;//屏幕日志输入static log4cpp::Priority::PriorityLevel logPri;//文件日志优先级static log4cpp::Priority::PriorityLevel coutPri;//屏幕日志优先级static log4cpp::PatternLayout* logLayout;//日志布局 static log4cpp::PatternLayout* screenLayout;//屏幕布局
public://获取日志函数,默认参数选择是否输出到屏幕static MyLog* getLog(bool toScreen = true,std::string coutName ="screenInfo",std::string logName = "log"){if(MyLog::log == NULL){MyLog::log = new MyLog(toScreen);MyLog::_logName = logName;MyLog::_screenInfo = coutName;logScreen = new log4cpp::OstreamAppender("logScreen",&std::cout);logFile = new log4cpp::FileAppender("logFile",MyLog::_logName);//设置布局MyLog::logLayout = new log4cpp::PatternLayout();MyLog::screenLayout = new log4cpp::PatternLayout();logLayout->setConversionPattern("%d{%Y/%m/%d,%H:%M:%S} -- [%p] %c: %m%n");screenLayout->setConversionPattern("%d{%Y/%m/%d %H:%M:%S} -- [%p] %c: %m%n");MyLog::logScreen->setLayout(screenLayout);MyLog::logFile->setLayout(logLayout);//追加到目录MyLog::logCat.addAppender(MyLog::logFile);MyLog::coutCat.addAppender(MyLog::logScreen);//设置优先级MyLog::logCat.setPriority(MyLog::logPri);MyLog::coutCat.setPriority(MyLog::coutPri);}MyLog::log->outToScreen = toScreen;return MyLog::log;}//销毁日志对象static void destoryLog(){log4cpp::Category::shutdown();delete MyLog::log;}//设置日志记录优先级static void setPri(log4cpp::Priority::PriorityLevel coutLevel,log4cpp::Priority::PriorityLevel logLevel){MyLog::logPri = logLevel;MyLog::coutPri = coutLevel;MyLog::logCat.setPriority(MyLog::logPri);MyLog::coutCat.setPriority(MyLog::coutPri);}//记录日志,调用参数__FILE__, __LINE__ ,__FUNCTION__void warn(const char * msg,const char *filename = __FILE__,int line = __LINE__,const char *function = "warn"){char info[4096] = {0};sprintf(info,"\nIn file %s,line %d,function %s:%s",filename,line,function,msg);if(this->outToScreen){logCat.warn(info);coutCat.warn(info);}else{logCat.warn(info);}}void error(const char * msg,const char *filename = __FILE__,int line = __LINE__,const char *function = "error"){char info[4096] = {0};sprintf(info,"\nIn file %s,line %d,function %s:%s",filename,line,function,msg);if(this->outToScreen){logCat.error(info);coutCat.error(info);}else{logCat.error(info);}}void debug(const char * msg,const char *filename = __FILE__,int line = __LINE__,const char *function = "debug"){char info[4096] = {0};sprintf(info,"\nIn file %s,line %d,function %s:%s",filename,line,function,msg);if(this->outToScreen){logCat.debug(info);coutCat.debug(info);}else{logCat.debug(info);}}void info(const char * msg,const char *filename = __FILE__,int line = __LINE__,const char *function = "info"){char info[4096] = {0};sprintf(info,"\nIn file %s,line %d,function %s:%s",filename,line,function,msg);if(this->outToScreen){logCat.info(info);coutCat.info(info);}else{logCat.info(info);}}
};
MyLog* MyLog::log = NULL;
std::string MyLog::_screenInfo = "screenInfo";
std::string MyLog::_logName = "log";log4cpp::Category& root = log4cpp::Category::getRoot();
log4cpp::Category& MyLog::logCat = root.getInstance(MyLog::_logName);
log4cpp::Category& MyLog::coutCat = root.getInstance(MyLog::_screenInfo);log4cpp::Priority::PriorityLevel MyLog::coutPri = log4cpp::Priority::INFO;
log4cpp::Priority::PriorityLevel MyLog::logPri = log4cpp::Priority::NOTSET;log4cpp::PatternLayout* MyLog::logLayout = NULL;
log4cpp::PatternLayout* MyLog::screenLayout = NULL;log4cpp::FileAppender* MyLog::logFile = NULL;//文件日志输入
log4cpp::OstreamAppender* MyLog::logScreen = NULL;//屏幕日志输入//为避免每次调用都要填写参数__FILE__,__LINE__和__FUNCTION__,可以使用带参数的宏定义
#define MyLogWARN(msg) MyLog::getLog()->warn(msg,__FILE__,__LINE__,__FUNCTION__);
#define MyLogINFO(msg) MyLog::getLog()->info(msg,__FILE__,__LINE__,__FUNCTION__);
#define MyLogERROR(msg) MyLog::getLog()->error(msg,__FILE__,__LINE__,__FUNCTION__);
#define MyLogDEBUG(msg) MyLog::getLog()->debug(msg,__FILE__,__LINE__,__FUNCTION__);
发送到远程服务器
应用程序中SocketAppender配置
前面启动了LoggingServer,下面说一下需要收集其日志的各个应用程序中配置。
说白了,就是在原来的基础上加一个SocketAppender,SocketAppender会自动将日志发送给loggingserver。这样直接在loggingserver上就可以查看所有服务器上的日志信息啦。哥终于不用再担心你们的运行状态啦!
配置文件
log4cplus.rootLogger=TRACE,STDOUT, ALL_MSGS,RemoteServer
log4cplus.logger.rollfile=TRACE,R2log4cplus.appender.STDOUT=log4cplus::ConsoleAppender
log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout
log4cplus.appender.STDOUT.layout.ConversionPattern=@@@[%d %d{%Z %Q}][pthread_id:%t][%l][%-5p][%c{2}] - %m%nlog4cplus.appender.R2=log4cplus::RollingFileAppender
log4cplus.appender.R2.File=./mytest.log
log4cplus.appender.R2.MaxFileSize=4MB
log4cplus.appender.R2.MaxBackupIndex=5
log4cplus.appender.R2.layout=log4cplus::PatternLayout
log4cplus.appender.R2.layout.ConversionPattern=@@@[%d %d{%Z %Q}][pthread_id:%t][%l][%-5p][%c{2}] - %m%n log4cplus.appender.RemoteServer=log4cplus::SocketAppender
log4cplus.appender.RemoteServer.host=192.168.2.130
log4cplus.appender.RemoteServer.port=9000
还可以输出到多个server,配置如下:
log4cplus.rootLogger=TRACE, STDOUT, ALL_MSGS,RemoteServer,RemoteServer2
log4cplus.logger.rollfile=TRACE,R2log4cplus.appender.STDOUT=log4cplus::ConsoleAppender
log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout
log4cplus.appender.STDOUT.layout.ConversionPattern=@@@[%d %d{%Z %Q}][pthread_id:%t][%l][%-5p][%c{2}] - %m%n
#log4cplus.appender.STDOUT.layout.ConversionPattern=@@@[%l][%-5p] - %m%nlog4cplus.appender.R2=log4cplus::RollingFileAppender
log4cplus.appender.R2.File=/opt/apps/3k/i1client/i1client.log
log4cplus.appender.R2.MaxFileSize=10000KB
log4cplus.appender.R2.MaxBackupIndex=100
log4cplus.appender.R2.layout=log4cplus::PatternLayout
log4cplus.appender.R2.layout.ConversionPattern=@@@[%d %d{%Z %Q}][pthread_id:%t][%l][%-5p][%c{2}] - %m%n
#log4cplus.appender.R2.layout.ConversionPattern=@@@[%l][%-5p] - %m%nlog4cplus.appender.RemoteServer=log4cplus::SocketAppender
log4cplus.appender.RemoteServer.host=192.168.2.130
log4cplus.appender.RemoteServer.port=9000log4cplus.appender.RemoteServer2=log4cplus::SocketAppender
log4cplus.appender.RemoteServer2.host=192.168.2.131
log4cplus.appender.RemoteServer2.port=9001
测试:
在Log4cplus的源码包中,有一个loggingServer目录,该目录中实现了一个LoggingServer。
在编译Log4cplus时,会自动编译该目录,在目录中生成loggingServer可执行文件,当然可以自己make(需要依赖log4cplus库)。
loggingServer使用方式如下:
./loggingserver 9000 log4cplus.properties
9000表示监听的端口号(不需要地址,默认监听本机地址)
log4cplus.properties是一个log4cplus的配置文件,和普通的log4cplus配置文件相同,loggingserver收到各个socket发来的日志后,根据配置文件信息,将其写入文件。
服务端配置文件如下
log4cplus.rootLogger=TRACE, STDOUT, ALL_MSGS#Appender输出位置类型:控制台输出
log4cplus.appender.STDOUT=log4cplus::ConsoleAppender
#日志输出格式 有词法分析功能的模式布局器
log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout
log4cplus.appender.STDOUT.layout.ConversionPattern=@@@[%d %d{%Z %Q}][pthread_id:%t][%l][%-5p][%c{2}] - %m%n#Appender输出位置类型有:文件输出 设置日志追加到文件尾
log4cplus.appender.ALL_MSGS=log4cplus::RollingFileAppender
#设置输出日志路径
log4cplus.appender.ALL_MSGS.File=log/i1client.log
#设置日志文件大小
log4cplus.appender.ALL_MSGS.MaxFileSize=1024KB
#设置生成日志最大个数
log4cplus.appender.ALL_MSGS.MaxBackupIndex=20
#日志输出格式 有词法分析功能的模式布局器
log4cplus.appender.ALL_MSGS.layout=log4cplus::PatternLayout
log4cplus.appender.ALL_MSGS.layout.ConversionPattern=@@@[%d %d{%Z %Q}][pthread_id:%t][%l][%-5p][%c{2}] - %m%n
相关文章:

c++日志工具之——log4cpp
1、log4cpp概述 Log4cpp是一个开源的C类库,它提供了C程序中使用日志和跟踪调试的功能,它的优点如下: 提供应用程序运行上下文,方便跟踪调试; 可扩展的、多种方式记录日志,包括命令行、文件、回卷文件、内…...

ES索引重建reindex详解
目录 一、使用场景 二、reindex介绍 三、使用手册 1、覆盖更新 2、创建丢失的文档并更新旧版本的文档 3、仅创建丢失的文档 4、冲突处理 5、source中添加查询条件 6、source中包含多个源索引 7、限制处理的记录数 8、从远程ES集群中重建索引 9、提取随机子集 10、…...

前沿分享-中距离射频取电
目前来看,微能源有四种技术路线,一是环境光采集、温差转换采集、无线射频采集和振动能量采集。 无线射频微能源是在通信设备通信过程中自然产生的,可以通过射频能量芯片实现无线射频取电,能瞬间大功率储电和安全驱动负载。 通过射…...

UnrealEngine - 网络同步之连接篇
1 连接过程 - 握手 传统的 C/S 架构下,Client 和 Server 通常会建立一条抽象的 Connection,用来进行两端的通信。 UE 的官方文档中提供了 Client 连接到 Server 的示例 ,简单来说分为如下几步: 打包构建好 Client 和 Server 进程…...

【JDBC系列】- 扩展提升学习
扩展提升学习 😄生命不息,写作不止 🔥 继续踏上学习之路,学之分享笔记 👊 总有一天我也能像各位大佬一样 🏆 博客首页 怒放吧德德 To记录领地 🌝分享学习心得,欢迎指正࿰…...

阻塞和非阻塞,同步和异步
文章目录 典型的一次IO的两个阶段IO多路复用是同步还是异步? 典型的一次IO的两个阶段 数据就绪和数据读写 同步:需要应用程序自己操作 IO多路复用是同步还是异步? epoll也是同步的 具体数据读取还是通过应用程序自己完成的 只有使用了特…...

提速Rust编译器!
Nethercote是一位研究Rust编译器的软件工程师。最近,他正在探索如何提升Rust编译器的性能,在他的博客文章中介绍了Rust编译器是如何将代码分割成代码生成单元(CGU)的以及rustc的性能加速。 他解释了不同数量和大小的CGU之间的权衡…...

QT创建项目
可选择CMake或qmake...

基于vue3+webpack5+qiankun实现微前端
一 主应用改造(又称基座改造) 1 在主应用中安装qiankun(npm i qiankun -S) 2 在src下新建micro-app.js文件,用于存放所有子应用。 const microApps [// 当匹配到activeRule 的时候,请求获取entry资源,渲染到containe…...
华为OD真题--完美走位--带答案
2023华为OD统一考试(AB卷)题库清单-带答案(持续更新)or2023年华为OD真题机考题库大全-带答案(持续更新) 题目描述 输入一个长度为4的倍数的字符串Q,字符串中仅包含WASD四个字母。 将这个字符串中的连续子串…...

【AI】《动手学-深度学习-PyTorch版》笔记(十四):多层感知机
AI学习目录汇总 1、多层感知机网络结构 1.1 线性模型:softmax回归 在前面介绍过,使用softmax回归来处理分类问题时,每个输出通过都一个仿射函数计算,网络结构如下,输入和输出之间为全链接层: 1.2 多层感知机 多层感知机就是在输入和输出中间再添加一个或多个全链接…...

本地开发 npm 好用的http server、好用的web server、静态服务器
好用的web server总结 有时需要快速启动一个web 服务器(http服务器)来伺服静态网页,安装nginx又太繁琐,那么可以考虑使用npm serve、http-server、webpack-dev-server。 npm serve npm 的serve可以提供给http server功能&#…...

Gradio入门,并搭个鸡兔同笼问题小应用,附源码(MindOpt)
应用链接: https://979427749bc9ceec34.gradio.live 是公开访问链接,3天有效。 在modelscope中的创空间发布长期有效:https://modelscope.cn/studios/wuyoy520v01/MindOpt_Chicken-with-rabbit-cage/summary。 应用图如下,源代码见正文。 知…...
redis核心知识点简略笔记
value数据类型 string 二进制安全 list 有序、可重复 set 无序、不重复 hash field-value的map sorted set 不重复、通过double类型score分数排序 场景 string 计数器缓存分布式锁访问频率控制分布式session hash 购物车等对象属性灵活修改 list 定时排行榜 set 收藏 sorte…...

消息中间件 —— 初识Kafka
文章目录 1、Kafka简介1.1、消息队列1.1.1、为什么要有消息队列?1.1.2、消息队列1.1.3、消息队列的分类1.1.4、p2p 和 发布订阅MQ的比较1.1.5、消息系统的使用场景1.1.6、常见的消息系统 1.2、Kafka简介1.2.1、简介1.2.2、设计目标1.2.3、kafka核心的概念 2、Kafka的…...

Ceph集群安装部署
Ceph集群安装部署 目录 Ceph集群安装部署 1、环境准备 1.1 环境简介1.2 配置hosts解析(所有节点)1.3 配置时间同步2、安装docker(所有节点)3、配置镜像 3.1 下载ceph镜像(所有节点执行)3.2 搭建制作本地仓库(ceph-01节点执行)3.3 配置私有仓库(所有节点执行)3.4 为 Docker 镜像…...
PXC基于docker搭建mysql集群全过程
之前用mysql自带的bin-log复制,总是因为各种冲突,同步就阻塞掉了,一旦阻塞掉了,不主动发现,同步就终止了。还需要想办法手动去处理。所以考虑重新搭建集群。发现PXC方案不错,可以上两台,对服务器…...

项目知识点记录
1.使用druid连接池 使用properties配置文件: driverClassName com.mysql.cj.jdbc.Driver url jdbc:mysql://localhost:3306/book?useSSLtrue&setUnicodetrue&charsetEncodingUTF-8&serverTimezoneGMT%2B8 username root password 123456 #初始化链接数…...
【HDFS】ListenableFuture在HDFS中的应用
本文主要介绍以下内容: ListenableFuture提供的功能和基本使用方法;AsyncLogger、IPCLoggerChannel(它是AsyncLogger的子类)QuorumCall类一、ListenableFuture的基本使用 ListenableFuture 是 Guava 库中提供的一个接口,它扩展了 JDK 中的 Future 接口,并添加了异步任务…...

Databend 开源周报第 105 期
Databend 是一款现代云数仓。专为弹性和高效设计,为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务:https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展,遇到更贴近你心意的 Databend 。 Databend 轻量级…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...