C++项目实战——基于多设计模式下的同步异步日志系统-⑫-日志宏全局接口设计(代理模式)
文章目录
- 专栏导读
- 日志宏&全局接口设计
- 全局接口测试
- 项目目录结构整理
- 示例代码
- 拓展示例代码
专栏导读
🌸作者简介:花想云 ,在读本科生一枚,C/C++领域新星创作者,新星计划导师,阿里云专家博主,CSDN内容合伙人…致力于 C/C++、Linux 学习。
🌸专栏简介:本文收录于 C++项目——基于多设计模式下的同步与异步日志系统
🌸相关专栏推荐:C语言初阶系列、C语言进阶系列 、C++系列、数据结构与算法、Linux
日志宏&全局接口设计
本章我们将完成提供全局接口&宏函数,对日志系统接口进行使用便捷性优化(避免用户自己创建单例)。
设计思想:
提供获取指定日志器的全局接口
(避免用户自己操作单例对象);使用宏函数对日志器的接口进行代理
(代理模式);提供宏函数,直接通过默认日志器进行日志的标准输出打印
(省去获取日志器的操作);
#ifndef __MY_LOG__
#define __MY_LOG__
#include "logger.hpp"namespace LOG
{// 1.提供获取指定日志器的全局接口(避免用户自己操作单例对象)Logger::ptr getLogger(const std::string &name){return LOG::LoggerManager::getInstance().getLogger(name);}Logger::ptr rootLogger(){return LOG::LoggerManager::getInstance().rootLogger();}// 2.实用宏函数对日志器的接口进行代理(代理模式)#define debug(fmt, ...) debug(__FILE__, __LINE__, fmt, ##__VA_ARGS__)#define info(fmt, ...) info(__FILE__, __LINE__, fmt, ##__VA_ARGS__)#define warn(fmt, ...) warn(__FILE__, __LINE__, fmt, ##__VA_ARGS__)#define error(fmt, ...) error(__FILE__, __LINE__, fmt, ##__VA_ARGS__)#define fatal(fmt, ...) fatal(__FILE__, __LINE__, fmt, ##__VA_ARGS__)// 3.提供宏函数,直接通过默认日志器进行日志的标准输出打印#define DEBUG(fmt, ...) LOG::rootLogger()->debug(fmt, ##__VA_ARGS__)#define INFO(fmt, ...) LOG::rootLogger()->info(fmt, ##__VA_ARGS__)#define WARN(fmt, ...) LOG::rootLogger()->warn(fmt, ##__VA_ARGS__)#define ERROR(fmt, ...) LOG::rootLogger()->error(fmt, ##__VA_ARGS__)#define FATAL(fmt, ...) LOG::rootLogger()->fatal(fmt, ##__VA_ARGS__)}
#endif
全局接口测试
测试代码
void log_test()
{DEBUG("%s", "测试日志");INFO("%s", "测试日志");WARN("%s", "测试日志");ERROR("%s", "测试日志");FATAL("%s", "测试日志");size_t count = 0;while(count < 300000){FATAL("测试日志-%d", count++);}
}
int main()
{log_test();return 0;
}
项目目录结构整理
示例代码
// example/test.cc
#include "../logs/log.h"
#include <unistd.h>void log_test(const std::string& name)
{INFO("%s", "测试开始");LOG::Logger::ptr logger = LOG::LoggerManager::getInstance().getLogger("async_logger");logger->debug(__FILE__, __LINE__, "%s", "测试日志");logger->info(__FILE__, __LINE__, "%s", "测试日志");logger->warn(__FILE__, __LINE__, "%s", "测试日志");logger->error(__FILE__, __LINE__, "%s", "测试日志");logger->fatal(__FILE__, __LINE__, "%s", "测试日志");INFO("%s", "测试完毕");
}
int main()
{std::unique_ptr<LOG::LoggerBuilder> builder(new LOG::GlobalLoggerBuilder());builder->buildLoggerName("async_logger");builder->buildLoggerLevel(LOG::LogLevel::value::WARN);builder->buildFormatter("[%c][%f:%l]%m%n");builder->buildLoggerType(LOG::LoggerType::LOGGER_ASYNC);builder->buildSink<LOG::FileSink>("./logfile/async.log");builder->buildSink<LOG::StdOutSink>();builder->buildSink<LOG::RollBySizeSink>("./logfile/roll-async-by-size", 1024 * 1024);builder->build();log_test("async_logger");return 0;
}
拓展示例代码
// extent/test.cc
#include "../logs/log.h"
#include <unistd.h>enum class TimeGap
{GAP_SECOND,GAP_MINUTE,GAP_HOUR,GAP_DAY
};
class RollByTimeSink : public LOG::LogSink
{
public:// 构造时传入文件名,并打开文件,将操作句柄管理起来RollByTimeSink(const std::string &basename, TimeGap gap_type) : _basename(basename){switch(gap_type){case TimeGap::GAP_SECOND: _gap_size = 1; break;case TimeGap::GAP_MINUTE: _gap_size = 60; break;case TimeGap::GAP_HOUR: _gap_size = 3600; break;case TimeGap::GAP_DAY: _gap_size = 3600 * 24; break;}_cur_gap = _gap_size == 1? LOG::util::Date::getTime() : LOG::util::Date::getTime() % _gap_size; // 获取当前是第几个时间段std::string filename = createNewFile();LOG::util::File::createDirectory(LOG::util::File::path(filename));_ofs.open(filename, std::ios::binary | std::ios::app);assert(_ofs.is_open());}// 将日志消息写入到标准输出,判断当前时间是否是当前文件的时间段,不是则切换文件void log(const char* data, size_t len){time_t cur = LOG::util::Date::getTime();if((cur % _gap_size) != _cur_gap){_ofs.close();std::string filename = createNewFile();_ofs.open(filename, std::ios::binary | std::ios::app);assert(_ofs.is_open());}_ofs.write(data, len);assert(_ofs.good());}
private:std::string createNewFile(){time_t t = LOG::util::Date::getTime();struct tm lt;localtime_r(&t, <);std::stringstream filename;filename << _basename;filename << lt.tm_year + 1900;filename << lt.tm_mon + 1;filename << lt.tm_mday;filename << lt.tm_hour;filename << lt.tm_min;filename << lt.tm_sec;filename << "-";filename << ".log";return filename.str();}
private:std::string _basename;size_t _gap_size; // 时间段的大小int _cur_gap; // 当前是第几个时间段std::ofstream _ofs;
};int main()
{std::unique_ptr<LOG::LoggerBuilder> builder(new LOG::GlobalLoggerBuilder());builder->buildLoggerName("async_logger");builder->buildLoggerLevel(LOG::LogLevel::value::WARN);builder->buildFormatter("[%c][%f:%l]%m%n");builder->buildLoggerType(LOG::LoggerType::LOGGER_ASYNC);builder->buildSink<LOG::FileSink>("./logfile/async.log");builder->buildSink<LOG::StdOutSink>();builder->buildSink<RollByTimeSink>("./logfile/roll-async-by-time", TimeGap::GAP_SECOND);LOG::Logger::ptr logger = builder->build();size_t cur = LOG::util::Date::getTime();while(LOG::util::Date::getTime() < cur + 5){logger->fatal("这是一条测试日志");}return 0;
}
相关文章:

C++项目实战——基于多设计模式下的同步异步日志系统-⑫-日志宏全局接口设计(代理模式)
文章目录 专栏导读日志宏&全局接口设计全局接口测试项目目录结构整理示例代码拓展示例代码 专栏导读 🌸作者简介:花想云 ,在读本科生一枚,C/C领域新星创作者,新星计划导师,阿里云专家博主,C…...

京东数据接口:京东数据分析怎么做?
电商运营中数据分析的重要性不言而喻,而想要做数据分析,就要先找到数据,利用数据接口我们能够更轻松的获得比较全面的数据。因此,目前不少品牌商家都选择使用一些数据接口来获取相关电商数据、以更好地做好数据分析。 鲸参谋电商…...
使用Git在本地创建一个仓库并将其推送到GitHub
前记: git svn sourcetree gitee github gitlab gitblit gitbucket gitolite gogs 版本控制 | 仓库管理 ---- 系列工程笔记. Platform:Windows 10 Git version:git version 2.32.0.windows.1 Function: 使用Git在本地创建一个…...

5.覆盖增强技术——PUCCHPUSCH
PUSCH增强方案的标准化工作 1.PUSCH重复传输类型A增强,包括两种增强机制:增加最大重复传输次数,以及基于可用上行时隙的重复传输次数技术方式。 2.基于频域的解决方案,包括时隙间/时隙内跳频的增强 3.支持跨多个时隙的传输块&…...

徐建鸿:深耕中医康养的“托钵行者”
为什么是“庄人堂”?杭州“庄人堂”医药科技公司董事长徐建鸿很乐意和别人分享这个名称的由来,一方面是庄子首先提出“养生”这个概念,接近上工治未病的上医,取名“庄人堂”代表庄子门生,向古哲先贤致敬!另…...

基于svg+js实现简单动态时钟
实现思路 创建SVG容器:首先,创建一个SVG容器元素,用于容纳时钟的各个部分。指定SVG的宽度、高度以及命名空间。 <svg width"200" height"200" xmlns"http://www.w3.org/2000/svg"><!-- 在此添加时钟…...

端到端测试(End-to-end tests)重试策略
作者|Giuseppe Donati,Trivago公司Web测试自动化工程师 整理|TesterHome 失败后重试,是好是坏? 为什么要在失败时重试所有测试?为什么不? 作为Trivago(德国酒店搜索服务平台&…...

三相交错LLC软启动控制驱动波形分析--死区时间与占空比关系
三相交错LLC软启动控制驱动波形分析 文章目录 三相交错LLC软启动控制驱动波形分析一、电路原理二、时序分析三、环路分析四、控制策略1.软启动驱动波形趋势2.软启动驱动波形占空图3.软启动驱动波形详细图4.软启动代码分析5.Debug调试界面5.死区时间与实际输出5.1 死区时间50--对…...

数据结构详细笔记——栈与队列
文章目录 栈的三要素逻辑结构(定义)数据的运算(基本操作)存储结构(物理结构)顺序栈(顺序存储)链栈(链式存储) 队列的三要素逻辑结构(定义…...

JVM调试命令与调试工具
目录 一、JDK自带命令 1、jps 2、jstat(FullGC频繁解决方案) 3、jmap 4、jhat 5、jstack(cpu占用高解决方案) 6、jinfo 二、JDK的可视化工具JConsole 1、JConsole 2、VisualVM 一、JDK自带命令 Sun JDK监控和故障处理命令如: 1、jps JVM Proc…...

《软件方法》第1章2023版连载(07)UML的历史和现状
DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 1.3 统一建模语言UML 1.3.1 UML的历史和现状 上一节阐述了A→B→C→D的推导是不可避免的,但具体如何推导,有各种不同的做法,这些做法可以称为“方…...
chromium 54 chrome 各个版本发布功能列表(109-119)
chromium Features 109-119 From https://chromestatus.com/features chromium109 Features:12 Auto range support for font descriptors inside font-face rule Auto range support for variable fonts in ‘font-weight’, ‘font-style’ and ‘font-stretch’ descrip…...

Linux实现原理 — I/O 处理流程与优化手段
Linux I/O 接口 Linux I/O 接口可以分为以下几种类型: 文件 I/O 接口:用于对文件进行读写操作的接口,包括 open()、read()、write()、close()、lseek() 等。 网络 I/O 接口:用于网络通信的接口,包括 socket()、conne…...

第 367 场 LeetCode 周赛题解
A 找出满足差值条件的下标 I 模拟 class Solution { public:vector<int> findIndices(vector<int> &nums, int indexDifference, int valueDifference) {int n nums.size();for (int i 0; i < n; i)for (int j 0; j < i; j)if (i - j > indexDiffe…...

最新百度统计配置图文教程,获取siteId、百度统计AccessToken、百度统计代码教程
一、前言 很多网友开发者都不知道百度统计siteId、百度统计token怎么获取,在网上找的教程都是几年前老的教程,因此给大家出一期详细百度统计siteId、百度统计token、百度统计代码获取详细步骤教程。 二、登录到百度统计 1.1 登录到百度统计官网 使用…...

【C++ 学习 ㉘】- 详解 C++11 的列表初始化
目录 一、C11 简介 二、列表初始化 2.1 - 统一初始化 2.2 - 列表初始化的使用细节 2.2.1 - 聚合类型的定义 2.2.2 - 注意事项 2.3 - initializer_list 2.3.1 - 基本使用 2.3.2 - 源码剖析 一、C11 简介 1998 年,C 标准委员会发布了第一版 C 标准࿰…...
OpenCV12-图像卷积
OpenCV12-图像卷积 图像卷积 图像卷积 OpenCV中提供了filt2D()函数用于实现图像和卷积模板之间的卷积运算: void filter2D(InputArray src, // 输入图像OutputArray dst, // 输出图像int ddepth, // 输出图像数据类型(深度)ÿ…...

MVCC与BufferPool缓存机制
MVCC多版本并发控制机制 Mysql在可重复读隔离级别下如何保证事务较高的隔离性,我们上节课给大家演示过,同样的sql查询语句在一个事务里多次执行查询结果相同,就算其它事务对数据有修改也不会影响当前事务sql语句的查询结果。 这个隔离性就是…...

POI、Easy Excel操作Excel
文章目录 1.常用的场景2.基本功能3.Excel在Java中是一个对象4. 简单的写(07版本(.xlsx)Excel)大文件写HSSF大文件写XSSF大文件写SXSSF 5. Excel读5.1 读取遇到类型转化问题该怎么解决5.2 遇到Excel公式怎么办 6. Easy Excel6.1简单…...

网络安全(黑客)自学方向
每年报考网络安全专业的人数很多,但不少同学听说千万别学网络安全,害怕网络安全专业很难就业。下面就带大家深入了解一下网络安全专业毕业后可以干什么,包括网络安全专业的就业前景和方向等。 随着信息化时代的到来,网络安全行业…...

华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...

高保真组件库:开关
一:制作关状态 拖入一个矩形作为关闭的底色:44 x 22,填充灰色CCCCCC,圆角23,边框宽度0,文本为”关“,右对齐,边距2,2,6,2,文本颜色白色FFFFFF。 拖拽一个椭圆,尺寸18 x 18,边框为0。3. 全选转为动态面板状态1命名为”关“。 二:制作开状态 复制关状态并命名为”开…...
接口 RESTful 中的超媒体:REST 架构的灵魂驱动
在 RESTful 架构中,** 超媒体(Hypermedia)** 是一个核心概念,它体现了 REST 的 “表述性状态转移(Representational State Transfer)” 的本质,也是区分 “真 RESTful API” 与 “伪 RESTful AP…...