kizumi_header_banner_img

Learn. Build. Share.

加载中

文章导读

基于脚手架微服务的视频点播系统-脚手架开发部分-gflags,gtest及splog中间件的认识与使用


avatar
xiu114514 2025年10月6日 186
基于脚手架微服务的视频点播系统-脚手架开发部分-gflags,gtest及splog中间件的认识与使用

脚手架开发的系统版本是ubuntu22.04-LTS,推荐配置为2核8G,硬盘大小为60GB.读者可自行选择使用虚拟机或云服务器进行开发。 源码链接(随文章进度更新):

https://gitee.com/ly121381/cpp-microservice-scaffold

我们对这些中间件的介绍与使用方法,不需要大家强制记下来,用到的时候忘记了,把文章当作手册再来看就可以了。第一遍就是混个眼熟,知道有这种用法就可以了。 @TOC

一.通过docker获取开发环境

我们这里使用的docker版本为28.4.0,docker-compose版本为2.13.0,推荐使用相同及更高版本进行环境获取。 首先我们先拉取事先准备好的开发环境: 拉取远端仓库:

拉取之后的仓库目录结构如下:

该环境的默认用户为dev密码为1,如有需要读者可以自行更改。然后使用命令:

启动容器环境,因为虚拟环境的端口映射为22:2222,所以我们新开一个ssh链接,改目标端口号为2222即可连接到虚拟开发环境中: 在这里插入图片描述 该虚拟环境已经配置好了所有的我们之后会使用到的中间件环境。所以我们接下来按照文章中所说的直接使用即可。不需要再去做额外配置了。大家可自行选择vscode,cursor等开发工具进行接下来的开发。

二.gflags的介绍使用

gflags是 Google 开发的⼀个开源库,⽤于 C++ 应⽤程序中命令行参数的声明、定义和解析。gflags 库提供了⼀种简单的方式来添加、解析和文档化命令⾏标志(flags),使得程序可以根据不同的运⾏时配置进行调整。 gflags的安装(我们虚拟环境中已经事先安装过,这里不需要再进行安装):

gflags的使用需要包含以下头文件:

编译时需要链接库-lgflags

2.1 定义参数

利⽤ gflags 提供的宏定义来定义参数。该宏的3个参数分别为命令⾏参数名,参数默认值,参数的帮助信息。

gflags⽀持定义多种类型的宏函数:

2.2访问参数

我们可以在程序中通过 FLAGS_reuse_addr 像正常变量⼀样访问标志参数。⽐如在上⾯的例⼦中,我们可以通过 FLAGS_log_level 和 FLAGS_log_file 变量来访问命令⾏参数。

2.3不同文件访问参数

如果想再另外⼀个⽂件访问当前⽂件的参数,以参数 FLAGS_reuse_addr 为例,我们可以使⽤宏 DECLARE_bool(reuse_addr) 来声明引⼊这个参数。其实这个宏就相当于做了 extern FLAGS_reuse_addr, 定义外部链接属性。

2.4初始化所有参数

当我们定义好参数后,需要告诉可执⾏程序去处理解析命令行传入的参数,使得 FLAGS_* 变量能得到正确赋值。我们需要在main函数中,调⽤下⾯的函数来解决命令行传入的所有参数。

argc 和 argv 就是 main 的⼊⼝参数 第三个参数被称为 remove_flags 。如果它为 true , 表示 ParseCommandLineFlags 会从argv 中移除标识和它们的参数,相应减少 argc 的值。如果它为false , ParseCommandLineFlags 会保留 argc 不变,但将会重新调整它们的顺序,使得标识再前⾯。

2.5运行参数设置

gflags为我们提供了多种命令⾏设置参数的⽅式。 string和int等类型设置参数

对于bool类型额外有一种特殊的设置方法

2.6配置文件的使用

配置⽂件的使⽤,其实就是为了让程序的运⾏参数配置更加标准化,不需要每次运⾏的时候都⼿动收 ⼊每个参数的数值,⽽是通过配置⽂件,⼀次编写,永久使⽤。 需要注意的是,配置⽂件中选项名称必须与代码中定义的选项名称⼀致,尤其需要注意的是配置⽂件中的字符串数据不需要使⽤双引号。 样例:

2.7其他特殊参数标识

2.8样例

编译使用到的makfile

第一种方式,通过命令行进行参数的设置:

可以看到没有设置的使用默认值,其他的与设置值相同。 第二种方式便是通过配置文件进行设置:

三.gtest的介绍与使用

GTest是⼀个跨平台的 C++单元测试框架,由google公司发布。gtest是为了在不同平台上为编C++单元测试而⽣成的。它提供了丰富的断⾔、致命和非致命判断、参数化等等测试所需的宏,以及全局测试,单元测试组件。

3.1安装

3.2使用介绍

3.2.1头文件包含

3.2.2框架初始化接口

3.2.3调用测试样例

3.2.4TEST宏

TEST:主要⽤来创建⼀个简单测试, 它定义了⼀个测试函数, 在这个函数中可以使⽤任何C++代码并且使⽤框架提供的断⾔进⾏检查 TEST_F:主要⽤来进⾏多样测试,适⽤于多个测试场景如果需要相同的数据配置的情况, 即相同的数据测不同的⾏为

3.2.5断言宏

GTest中的断⾔的宏可以分为两类: • ASSERT系列:如果当前点检测失败则退出当前函数
• EXPECT
系列:如果当前点检测失败则继续往下执⾏
下⾯是经常使⽤的断⾔介绍

3.6样例

你也可以不返回RUN_ALL_TESTS(),因为它就相当于我们程序出问题时返回-1一样,当他有用例不通过时返回的便不为0.所以可以选择返回也可以选择不返回,具体看我们的使用场景。

3.3事件机制

GTest中的事件机制是指在测试前和测试后提供给⽤⼾⾃⾏添加操作的机制,⽽且该机制也可以让同⼀测试套件下的测试⽤例共享数据。GTest框架中事件的结构层次: 在这里插入图片描述 测试程序:⼀个测试程序只有⼀个main函数,也可以说是⼀个可执⾏程序是⼀个测试程序。该级别的事件机制是在程序的开始和结束执⾏ 测试套件:代表⼀个测试⽤例的集合体,该级别的事件机制是在整体的测试案例开始和结束执⾏ 测试⽤例:该级别的事件机制是在每个测试⽤例开始和结束都执⾏ 事件机制的最⼤好处就是能够为我们各个测试⽤例提前准备好测试环境,并在测试完毕后⽤于销毁环境,这样有个好处就是如果我们有⼀端代码需要进⾏多种不同⽅法的测试,则可以通过测试机制在每个测试⽤例进⾏之前初始化测试环境和数据,并在测试完毕后清理测试造成的影响。 GTest提供了三种常⻅的的事件:

3.3.1全局事件

如果我们有测试数据需要在所有测试开始前进行初始化在所有测试后进行清理。需要创建⼀个⾃⼰的类,然后继承testing::Environment类,然后分别实现成员函数 SetUp 和 TearDown ,同时在main函数内进⾏调⽤testing::AddGlobalTestEnvironment(new MyEnvironment); 函数添加全局的事件机制:

运行结果:

3.3.2TestSuite事件

如果说我们想要将多个测试分为不同的组,然后不同的组又各自需要自己的测试环境,需要在每组的测试开始前去初始化环境,结束时清理环境。我们同样需要去创建⼀个类,继承⾃ testing::Test ,实现两个静态函数 SetUpTestCase 和 TearDownTestCase ,测试套件的事件机制不需要像全局事件机制⼀样在 main 注册,⽽是需要将我们平时使⽤的 TEST 宏改为 TEST_F 宏。 SetUpTestCase() 函数是在测试套件第⼀个测试⽤例开始前执⾏ TearDownTestCase() 函数是在测试套件最后⼀个测试⽤例结束后执⾏ 需要注意TEST_F的第⼀个参数是我们创建的类名,也就是当前测试套件的名称,这样在TEST_F宏的测试套件中就可以访问类中的成员了。

3.3.3TestCase事件

如果我们每个测试都需要在当前测试开始时去初始化环境,在当前测试结束时清理环境,也就是说每个测试用到的环境是独立的,我们针对⼀个个测试⽤例。测试⽤例的事件机制的创建和测试套件的基本⼀样,不同地⽅在于测试⽤例实现的两个函数分别是 SetUp 和 TearDown , 这两个函数也不是静态函数: SetUp()函数是在⼀个测试⽤例的开始前执⾏ TearDown()函数是在⼀个测试⽤例的结束后执⾏ 也就是说,在TestSuite/TestCase事件中,每个测试⽤例,虽然它们同⽤同⼀个事件环境类,可以访问其中的资源,但是本质上每个测试⽤例的环境都是独⽴的,这样我们就不⽤担⼼不同的测试⽤例之间会有数据上的影响了,保证所有的测试⽤例都使⽤相同的测试环境进⾏测试。

四.spdlog的介绍与二次封装

spdlog 是⼀个⾼性能、超快速、零配置的 C++ ⽇志库,它旨在提供简洁的 API 和丰富的功能,同时保持⾼性能的⽇志记录。它⽀持多种输出⽬标、格式化选项、线程安全以及异步⽇志记录。以下是对 spdlog 的详细介绍和使⽤⽅法。 github源码链接: https://github.com/gabime/spdlog

4.1安装

命令安装:

源码安装:

4.2使用

4.2.1头文件包含

4.2.2日志输出等级枚举

4.2.3日志输出格式自定义

4.2.4 日志记录类

⽇志记录器类是spdlog中⽤于进⾏⽇志输出的类,内部定义了各种不同等级⽇志的输出接⼝,同时,也可以在该类中设置⽇志的输出格式以及输出级别等基础配置。

4.2.5异步日志记录类

为了异步记录⽇志,可以使⽤ spdlog::async_logger ,其总体的常规操作与同步⽇志器并⽆区别,区别仅在于⽇志数据的写⼊⽅式有所不同,异步⽇志器的使⽤会伴随创建⼀个异步线程池(默认只有⼀个线程)进⾏⽇志的实际写⼊操作。

4.2.6日志记录器工厂

⽇志器⼯⼚是⽤于快速创建⽇志器对象的⼯⼚类,spdlog中默认提供了两种不同的⽇志器⼯⼚类,⼀种是同步⽇志器⼯⼚(默认),⼀种是异步⽇志器⼯⼚,⼯⼚的选择通过⽇志器创建函数模板的模板参数进⾏设置。

4.2.7日志落地类

⽇志落地类,负责决定将⽇志数据写⼊到哪些设备中,在spdlog中,实现了⾮常多的落地⽅向,这⾥贴出了标准输出,普通⽂件,滚动⽂件等⼏种常⽤对象的创建⽅式。 除此之外,还可以在该类中进⼀步细化设置⽇志的输出格式,输出等级等配置(或者说其实spdlog中有很多地⽅都可以设置⽇志输出等级和输出格式,但是实际都会归总到⽇志落地类中进⾏最后的⽇志格式组织,以及判断是否该输出等操作)。

4.2.8全局配置接⼝

可以通过⼀些spdlog命名空间下的全局接⼝,对全局的⽇志输出进⾏配置(⼀旦配置则对全局⽣效)。

4.2.9记录日志

使⽤⽇志记录器记录不同级别的⽇志:

4.2.10使用示例

根据上面的相关接口介绍,我们可以得到如下的使用流程: 1.设置日志为同步/异步属性 2.设置日志的输出目标:标准输出/标准错误输出/文件输出/循环文件输出 3.设置日志的输出格式 4.设置日志的最低输出级别 5.输出日志 所以我们可以得到如下的一个使用示例:

读者可自行去除注释或增加注释去运行代码。需要特别说明的是循环文件输出的最后的bool参数设置,有兴趣的读者可以自行进行了解下,问下ai很容易就能了解他们的区别了。因为我们封装的时候只关心是否同步或异步,输出方向是标准输出还是文件输出,以及日志输出格式和日志输出最低级别。所以我们这里不再深入介绍。

4.3二次封装

我们在写客户端是是通过宏的方式去使用日志的,所以这里我们也是最终封装成可以通过宏进行日志输出的方式: 设计思路如下: 1.定义日志设置的结构体,此结构体中包含同步/异步开启,输出方向,日志输出格式及日志输出最低级别 2.在使用日志前通过该结构体对全局日志对象进行初始化 3.封装日志输出宏 封装结果如下:

##VA_ARGS表示是一个可变参数,我们使用封装日志时是这样的ERR("{}1231",arg),如果没有额外参数,##VA_ARGS会自动去掉它前面的那个,避免出现宏替换后limelog::g_logger->error(FMT_PREFIX + fmt, FILE, LINE,)这样的情况。

 



评论(已关闭)

评论已关闭

日历

2025 年 10 月
 123456
78910111213
14151617181920
21222324252627
282930