【高并发服务器】六、日志宏的实现 - 指南

news/2025/11/15 11:36:27/文章来源:https://www.cnblogs.com/yangykaifa/p/19224787

文章目录

  • 日志宏封装

在这里插入图片描述

日志宏封装

​ 目的就是为了实现一些宏函数,让它们辅助我们进行日志信息的打印,我们想要的格式像下面这样子:

[2023/6/21 21:28:30 main.c:28] 文件打开失败

​ 也就是这样子:

[时间 出现错误的文件:行号] 错误信息

​ 对于出现错误的文件和行号来说其实不难,因为 C 语言本身就给我们提供了对应的宏,分别是 __FILE____LINE__

​ 而对于时间来说,这得用几个函数来帮忙:

// 获取系统时间戳
time_t time(NULL);
// 通过系统时间戳参数来获取本地时间的结构体tm
struct tm* localtime(time_t* t);
// 将结构体tm通过format形式根据max大小存放到buf中去
char* strftime(char* buf, int max, char* format, struct tm* tm);
// 通过format格式将可变参数写到文件指针所指的文件中去
int fprintf(FILE* fp, char* format, ...);

​ 我们的日志宏和服务器头文件 server.hpp 放在一起。因为我们要用到宏,那么就得用 <cstdio> 头文件,所以要将其包含进来。

​ 接着我们写一个简单宏定义:

#ifndef __MY_LOG_H__
#define __MY_LOG_H__
#include <cstdio>#define LOG(format, ...) fprintf(stdout, "[%s:%d] " format, __FILE__, __LINE__, __VA_ARGS__)#endif

​ 这里的 LOG 就是一个日志宏,它的第一个参数是一个格式化字符串 format,用于指定输出信息的格式,注意 format 只是我们在宏定义常常起的参数名,并不是一个关键字或预定义标识符

LOG 的第二个参数 ... 是 可变参数列表的一种表示,而 fprintf 函数中的 __VA_ARGS__C 语言中的一个预处理器宏,也是用于表示一个可变参数列表,当我们调用 LOG 宏的时候,... 中的多个可变参数都会在预处理阶段传递给 __VA_ARGS__

​ 比如说下面的例子:

LOG("%s: %d", "liren", 10);
最后在预处理阶段会被替换为如下形式:
fprintf(stdout, "[%s:%d] %s: %d", __FILE, __LINE, "liren", 10);

​ 至于具体 __VA_ARGS__ ... 的区别可以看下面这段理解!

__VA_ARGS__ ... 的区别:

​ 它们用来表示可变参数列表的语法元素,但它们的使用方式和作用范围有所不同。

... 是 C99 标准引入的 语法,用于表示函数或宏定义中的可变参数列表。在函数定义或宏定义中,... 必须放在参数列表的最后一个位置,用来表示后面还有一些可变数量的参数。例如,下面是一个使用 ... 表示可变参数的函数定义:

void my_printf(const char* format, ...);

​ 在函数调用时,可以使用类似于 printf 函数的方式传递可变数量的参数,例如:

my_printf("The value of x is %d\n", x);
my_printf("Hello, %s!\n", name);

​ 在这种情况下,编译器会将可变参数列表转换为一个类型为 va_list 的对象,然后可以使用 stdarg.h 中定义的函数和宏如 va_start()vsnprintf() 等来访问和处理这些参数。

__VA_ARGS__ 则是一个预处理器宏,用于表示宏定义中的可变参数列表。在宏定义中,__VA_ARGS__ 可以出现在参数列表的任意位置,用来表示可变数量的参数。例如,下面是一个使用 __VA_ARGS__ 表示可变参数的宏定义:

#define LOG(format, ...) printf(format, __VA_ARGS__)

​ 在这种情况下,预处理器会将 __VA_ARGS__ 展开为一系列逗号分隔的参数,然后将它们传递给宏定义中的 printf 函数进行输出。但是一般防止不传可变列表参数报错,我们会 __VA_ARGS__ 前面加上 ## 表示展开后的可变参数列表,如下所示:

#define LOG(format, ...) printf(format, ##__VA_ARGS__)

​ 并且 上面的 printf 中使用的时候是不能用 ... 的,只能使用 __VA_ARGS__ 来表示接收到的可变参数列表

​ 总的来说,...__VA_ARGS__ 都是用来表示可变参数列表的语法元素,但是 前者用于函数定义和函数调用中后者只能用于宏定义中。它们的作用和使用方式有所不同,但都可以方便地处理可变数量的参数。

​ 接下来我们再来加入时间等信息,让宏日志更完善一点!一般我们如果想要在宏定义的时候写多行代码,都会使用 do while(0) 语句来配合,涉及到换行的话要使用反斜杠 \ 在语句最后面,下面给出结合打印时间的代码的完善日志宏:

#include <cstdio>#include <time.h>#define LOG(format, ...) do{\char timebuffer[128];\time_t timestamp = time(NULL);\struct tm* timeinfo = localtime(&timestamp);\strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S", timeinfo);\fprintf(stdout, "[%s %s:%d] " format, timebuffer, __FILE__, __LINE__, __VA_ARGS__);\}while(0)

​ 调用的结果如下:

LOG("%s-%d\n", "liren", 100);
结果:
[2023-06-21 23:17:03 gobang.cc:5] liren-100

​ 这样子就结束了吗❓❓❓

​ 当然不是,因为还有 bug,因为如果我们 使用 LOG 宏的时候不传可变参数的话,那么预处理时候就会报错,如下所示:

LOG("liren");
编译时候会报错:
[liren@VM-8-7-centos source]$ make
g++ -ogobang gobang.cc logger.hpp
In file included from gobang.cc:1:0:
gobang.cc: In function ‘int main():
logger.hpp:11:86: error: expected primary-expression before ‘)’ token
intf(stdout, "[%s %s:%d] " format, timebuffer, __FILE__, __LINE__, __VA_ARGS__);\
^
gobang.cc:5:5: note: in expansion of macro ‘LOG’
LOG("liren");
^~~
make: *** [makefile:2: gobang] Error 1

​ 解决这个问题很简单,只需要使用 ##__VA_ARGS__ 来表示展开后的参数列表。这个语法中的 ## 表示将 __VA_ARGS__ 前面的逗号去掉,避免在展开后出现语法错误!需要注意的是,## 的使用在不同的编译器和平台上可能有所不同。在使用 ## 时需要注意平台兼容性和语法规则。

​ 所以修改完代码如下:

#include <cstdio>#include <time.h>#define LOG(format, ...) do{\char timebuffer[128] = {0};\time_t timestamp = time(NULL);\struct tm* timeinfo = localtime(&timestamp);\strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S", timeinfo);\fprintf(stdout, "[%s %s:%d] " format "\n", timebuffer, __FILE__, __LINE__, ##__VA_ARGS__);\}while(0)

​ 这样子就结束了吗❓❓❓还是没结束,因为我们到时候项目中会打印很多日志,如果我们不对日志分等级的话,那么可能会导致日志比较乱,下面我们定义一些等级的宏:

#define INF 0    // 提示型等级
#define DEBUG 1  // 调试型等级
#define ERROR 2  // 错误型等级
#define DEFAULT_LOG_LEVEL DEBUG  // 默认的日志等级

​ 然后我们再将这些等级宏和我们刚才写的日志宏封装起来:

#define ILOG(format, ...) LOG(INF, format, ##__VA_ARGS__)
#define DLOG(format, ...) LOG(DEBUG, format, ##__VA_ARGS__)
#define ELOG(format, ...) LOG(ERROR, format, ##__VA_ARGS__)

​ 此时看到 LOG 宏的第一个参数传入的是对应的等级,那我们想要去改一下原来的日志宏的参数,多加一个参数 level,并且我们判断一下当前的等级也就是 DEFAULT_LOG_LEVEL是否小于传入进来的等级,是的话我们就不需要去打印,因为我们此时程序说明不需要上升到这种级别的日志打印!

#define LOG(level, format, ...) do{\
if(DEFAULT_LOG_LEVEL > level) break\
char timebuffer[128] = {0};\
time_t timestamp = time(NULL);\
struct tm* timeinfo = localtime(&timestamp);\
strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S", timeinfo);\
fprintf(stdout, "[%s %s:%d] " format "\n", timebuffer, __FILE__, __LINE__, ##__VA_ARGS__);\
}while(0)

​ 所以完整的代码是这样子的:

#include <cstdio>#include <time.h>#define INF 0    // 提示型等级#define DEBUG 1  // 调试型等级#define ERROR 2  // 错误型等级#define DEFAULT_LOG_LEVEL DEBUG  // 默认的日志等级#define LOG(level, format, ...) do{\if(DEFAULT_LOG_LEVEL < level) break;\char timebuffer[128] = {0};\time_t timestamp = time(NULL);\struct tm* timeinfo = localtime(&timestamp);\strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S", timeinfo);\fprintf(stdout, "[%s %s:%d] " format "\n", timebuffer, __FILE__, __LINE__, ##__VA_ARGS__);\}while(0)// 将等级和日志打印封装起来#define ILOG(format, ...) LOG(INF, format, ##__VA_ARGS__)#define DLOG(format, ...) LOG(DEBUG, format, ##__VA_ARGS__)#define ELOG(format, ...) LOG(ERROR, format, ##__VA_ARGS__)

​ 下面我们测试一下:

ILOG("this is INF");
DLOG("this is DEBUG");
ELOG("this is ERROR");
// 运行结果:
[liren@VM-8-7-centos source]$ ./gobang
[2023-06-21 23:41:55 gobang.cc:5] this is INF
[2023-06-21 23:41:55 gobang.cc:6] this is DEBUG

在这里插入图片描述

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

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

相关文章

2025年评价高的磁悬浮冷水机厂家最新推荐权威榜

2025年评价高的磁悬浮冷水机厂家最新推荐权威榜 行业背景与市场趋势 随着工业制造技术的不断升级,磁悬浮冷水机凭借高效节能、低噪音、长寿命等优势,逐渐成为温控设备市场的主流选择。据《2024年中国工业制冷设备市…

2025年白色珍珠棉卷材生产商权威推荐榜单:珍珠棉袋子/EPE珍珠棉板材/白色珍珠棉板材源头厂家精选

在当前工业包装领域,白色珍珠棉卷材因其优异的缓冲性能和环保特性,已成为精密仪器、电子设备、汽车配件等行业不可或缺的包装材料。据行业调研数据显示,珍珠棉卷材市场需求年均增长率保持在8%以上,在包装材料中的占…

2025年热门的防腐耐磨涂层厂家最新权威实力榜

2025年热门的防腐耐磨涂层厂家最新权威实力榜行业背景与市场趋势防腐耐磨涂层行业作为工业防护领域的重要组成部分,近年来随着制造业升级和环保要求提高,迎来了快速发展期。根据《2024-2029年中国防腐涂料行业市场调…

2025年口碑好的称重模块传感器品牌厂家排行榜

2025年口碑好的称重模块传感器品牌厂家排行榜行业背景与市场趋势称重模块传感器作为工业自动化、物流运输、食品医药等领域的关键测量设备,近年来随着智能制造和物联网技术的普及,市场需求持续增长。据《2024-2029年…

详细介绍:k8s(七)pod的配置资源管理

详细介绍:k8s(七)pod的配置资源管理pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mon…

2025年知名的一字阻尼铰链热门厂家推荐榜单

2025年知名的一字阻尼铰链热门厂家推荐榜单行业背景与市场趋势随着家居五金行业向智能化、人性化方向发展,一字阻尼铰链作为现代家具的核心配件,其市场需求持续增长。据《2024-2025中国家居五金行业白皮书》显示,全…

英语_阅读_ancient school_待读

What was school like in ancient times? 古代的学校是什么样的? In Greece, 2,500 years ago, students used to get up at dawn to go to school. 在2500年前的希腊,学生们通常在黎明时分起床去上学。 Classes be…

零售场景下的数智店商:解决盗损问题,化解隐性成本痛点

在零售行业,盗损问题始终是商家挥之不去的痛点。无论是顾客在生鲜区将进口水果藏入背包的偷盗行为,还是在化妆品区随意撕开试用装的违规拆包,亦或是电子产品区因意外碰撞导致商品损坏,这些隐性损失不仅侵蚀利润,还…

2025年11月北京高考辅导机构权威榜:五强对比与客观排行一览

2025年11月,北京高三学生已陆续进入期中诊断,距离次年高考不足二百天。家长群里“冲刺班”“押题营”刷屏,线下宣讲会一座难求,线上广告更是精准推送到家长手机。焦虑背后,是同一串疑问:时间紧、任务重,哪家辅导…

2025年轻奢营地帐篷直销厂家权威推荐榜单:度假营地帐篷/住宿营地帐篷/营地住宿帐篷源头厂家精选

随着精致露营消费升级,轻奢营地帐篷市场正迎来快速增长期。据2024年户外休闲产业数据显示,中国露营经济核心市场规模已突破580亿元,其中轻奢帐篷在营地装备采购中占比达23.5%,三年复合增长率达18.7%。 轻奢帐篷作为…

2025年靠谱的汇众汽配刹车盘行业内知名厂家排行榜

2025年靠谱的汇众汽配刹车盘行业内知名厂家排行榜行业背景与市场趋势随着中国汽车保有量的持续增长和汽车后市场的蓬勃发展,刹车盘作为汽车制动系统的核心部件,其市场需求呈现稳定上升态势。根据中国汽车工业协会最新…

2025年评价高的神州飞碟游乐设施厂家推荐及选择参考

2025年评价高的神州飞碟游乐设施厂家推荐及选择参考一、行业背景与市场趋势近年来,中国游乐设施行业呈现快速发展态势。根据中国游艺机游乐园协会数据,2023年中国大型游乐设施市场规模已突破200亿元,预计2025年将达…

2025年11月中国境外券商投行机构排行榜:跨境上市通道资源与牌照对比

“境外上市”四个字背后,往往是一家企业从初创到规模化的关键一跃。创始人通常面临三大痛点:一是境外监管规则复杂,稍有疏漏即被驳回;二是中介链条长,保荐、承销、法律、审计各自为政,沟通成本高;三是后续市值管…

2025年热门的地面瓷砖胶厂家推荐及选择建议

2025年热门的地面瓷砖胶厂家推荐及选择建议行业背景与市场趋势随着中国建筑行业的持续发展和装修标准的不断提高,地面瓷砖胶作为建筑装饰工程中的重要辅材,其市场需求呈现稳定增长态势。根据中国建筑材料联合会最新发…

2025年11月中国境外券商投行机构评价榜:顺安资本携四席真实数据对比

2025年11月,当企业计划赴纽约、香港或新加坡挂牌,却面对境外券商投行机构“牌照是否齐全、案例是否真实、服务能否覆盖全周期”三大疑问时,一份基于公开牌照库、监管公告与交易所披露案例的横向对比就显得格外必要。…

2025年评价高的三节缓冲同步隐藏轨厂家最新权威实力榜

2025年评价高的三节缓冲同步隐藏轨厂家最新权威实力榜行业背景与市场趋势随着家居五金行业向智能化、高端化方向发展,三节缓冲同步隐藏轨作为现代家具的核心配件,其市场需求持续增长。据《2024-2025中国家居五金行业…

2025年专业的玻璃钢化粪池用户好评厂家排行

2025年专业的玻璃钢化粪池用户好评厂家排行行业背景与市场趋势玻璃钢化粪池作为一种新型环保产品,近年来在我国污水处理领域得到了广泛应用。根据中国环保产业协会最新发布的《2024-2025年中国玻璃钢制品行业分析报告…

题解:P8648 [蓝桥杯 2017 省 A] 油漆面积

洛谷题解:P8648 [蓝桥杯 2017 省 A] 油漆面积一道差分题。 题目大意 给出 \(n\) 个矩阵,每个矩阵可能互相重叠。求被矩阵覆盖的面积有多少? 题目分析 很多大佬说要用扫描线。但是我太蒻了,也不会扫描线。于是这里给…

2025年正规的轻集料混凝土LC7.5型厂家推荐及选购参考榜

2025年正规的轻集料混凝土LC7.5型厂家推荐及选购参考榜行业背景与市场趋势轻集料混凝土作为一种新型建筑材料,近年来在我国建筑行业得到了广泛应用。根据中国建筑材料联合会最新发布的《2024-2025年中国轻集料混凝土行…

2025年聚合氯化铝直销厂家权威推荐榜:聚合氯化铝喷雾/30聚合氯化铝/碱式聚合氯化铝源头厂家精选

精选全国优质聚合氯化铝直供企业,降本增效的水处理解决方案触手可及。 在当前环保要求日益严格的水处理领域,聚合氯化铝作为使用广泛的高效絮凝剂,其质量与供应商选择直接关系到处理效果与运营成本。 本文将聚焦聚合…