C++基于多设计模式下的同步异步日志系统day4

📟作者主页:慢热的陕西人

🌴专栏链接:C++基于多设计模式下的同步&异步日志系统

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

只要内容主要实现了同步日志消息的建造者模式的实现

在这里插入图片描述

文章目录

  • C++基于多设计模式下的同步&异步日志系统day4
    • 1.⽇志器类(Logger)设计(建造者模式)

C++基于多设计模式下的同步&异步日志系统day4

1.⽇志器类(Logger)设计(建造者模式)

⽇志器主要是⽤来和前端交互,当我们需要使⽤⽇志系统打印log的时候,只需要创建Logger对象,调⽤该对象debug、info、warn、error、fatal等⽅法输出⾃⼰想打印的⽇志即可,⽀持解析可变参数列表和输出格式,即可以做到像使⽤printf函数⼀样打印⽇志。
当前⽇志系统⽀持同步⽇志&异步⽇志两种模式,两个不同的⽇志器唯⼀不同的地⽅在于他们在⽇志的落地⽅式上有所不同:

  • 同步⽇志器:直接对⽇志消息进⾏输出。
  • 异步⽇志器:将⽇志消息放⼊缓冲区,由异步线程进⾏输出。

因此⽇志器类在设计的时候先设计出⼀个Logger基类,在Logger基类的基础上,继承出SyncLogger同步⽇志器和AsyncLogger异步⽇志器。且因为⽇志器模块是对前边多个模块的整合,想要创建⼀个⽇志器,需要设置⽇志器名称,设置⽇志输出等级,设置⽇志器类型,设置⽇志输出格式,设置落地⽅向,且落地⽅向有可能存在多个,整个⽇志器的创建过程较为复杂,为了保持良好的代码⻛格,编写出优雅的代码,因此⽇志器的创建这⾥采⽤了建造者模式来进⾏创建。

/*完成日志器模块:1.抽象日志器基类2.派生出不同的子类(同步日志器类 & 异步日志器类)*/
#ifndef __M_LOGER_H__
#define __M_LOGER_H__#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include"format.hpp"
#include"level.hpp"
#include"message.hpp"
#include"sink.hpp"
#include"util.hpp"#include<atomic>
#include<stdio.h>
#include<mutex>
#include<stdarg.h>
#include<cassert>namespace xupt
{class Logger{public:using ptr = std::shared_ptr<Logger>;Logger(const std::string& logger_name,LogLevel::value level,Formatter::ptr &formatter,std::vector<LogSink::ptr> sinks):_logger_name(logger_name),_limit_level(level),_formatter(formatter),_sinks(sinks.begin(), sinks.end()){}/*完成日志构造消息,并进行格式化,得到格式化后的日志消息字符串---然后进行落地输出*/void debug(const std::string &file, size_t line, const std::string &fmt, ...){//1.判断当前的日志是否到达了输出等级if(LogLevel::value::DEBUG < _limit_level) { return ; }va_list ap;va_start(ap, fmt);char* res;int ret = vasprintf(&res, fmt.c_str(), ap);if(ret == -1){std::cout << "vasprintf failed!\n";return ;}va_end(ap); //将ap置空serialize(LogLevel::value::DEBUG, file, line, res);free(res);}void info(const std::string &file, size_t line, const std::string &fmt, ...){//1.判断当前的日志是否到达了输出等级if(LogLevel::value::INFO < _limit_level) { return ; }va_list ap;va_start(ap, fmt);char* res;int ret = vasprintf(&res, fmt.c_str(), ap);if(ret == -1){std::cout << "vasprintf failed!\n";return ;}va_end(ap); //将ap置空serialize(LogLevel::value::INFO, file, line, res);free(res);}        void warn(const std::string &file, size_t line, const std::string &fmt, ...){//1.判断当前的日志是否到达了输出等级if(LogLevel::value::WARN < _limit_level) { return ; }va_list ap;va_start(ap, fmt);char* res;int ret = vasprintf(&res, fmt.c_str(), ap);if(ret == -1){std::cout << "vasprintf failed!\n";return ;}va_end(ap); //将ap置空serialize(LogLevel::value::WARN, file, line, res);free(res);}             void error(const std::string &file, size_t line, const std::string &fmt, ...){//1.判断当前的日志是否到达了输出等级if(LogLevel::value::ERROR < _limit_level) { return ; }va_list ap;va_start(ap, fmt);char* res;int ret = vasprintf(&res, fmt.c_str(), ap);if(ret == -1){std::cout << "vasprintf failed!\n";return ;}va_end(ap); //将ap置空serialize(LogLevel::value::ERROR, file, line, res);free(res);}             void fatal(const std::string &file, size_t line, const std::string &fmt, ...){//1.判断当前的日志是否到达了输出等级if(LogLevel::value::FATAL < _limit_level) { return ; }va_list ap;va_start(ap, fmt);char* res;int ret = vasprintf(&res, fmt.c_str(), ap);if(ret == -1){std::cout << "vasprintf failed!\n";return ;}va_end(ap); //将ap置空serialize(LogLevel::value::FATAL, file, line, res);free(res);}     protected:void serialize(LogLevel::value level, const std::string &file, size_t line, char* str){//2.构造LogMsg对象LogMsg msg(level, line, file, _logger_name, str);//3.通过格式化工具对LogMsg进行格式化,得到格式化后的日志字符串std::stringstream ss;_formatter->format(ss, msg);//5.进行日志落地log(ss.str().c_str(), ss.str().size());}/*抽象接口完成实际的落地输出--不同的日志器会有不同的实际落地方式*/virtual void log(const char *data, size_t len) = 0;protected:std::mutex _mutex;                         // 保证过程的线程安全std::string _logger_name;                  // 日志器名称std::atomic<LogLevel::value> _limit_level; // 日志等级Formatter::ptr _formatter;                 // 格式化std::vector<LogSink::ptr> _sinks;          // 用一个数组来存放日志落地位置};//同步日志器class SyncLogger : public Logger{public:SyncLogger(const std::string& logger_name,LogLevel::value level,Formatter::ptr &formatter,std::vector<LogSink::ptr> sinks):Logger(logger_name, level, formatter, sinks){}protected:virtual void log(const char *data, size_t len){std::unique_lock<std::mutex> lock(_mutex);if(_sinks.empty()) return;for(auto &sink : _sinks){sink->log(data,len);}}};enum class LoggerType{LOGGER_SYNC,LOGGER_ASYNC};/*使用建造者模式来建造日志器,而不用用户直接去构造日志器,减少用户的使用复杂度*///1.抽象一个日志器建造者类(完成日志器对象所需零部件的构造 & 日志器的构建)//  1.设置日志器类型//  2.将不同类型日志器的创建放到同一个日志器建造类中完成class LoggerBuilder{public:LoggerBuilder():_logger_type(LoggerType::LOGGER_SYNC),_limit_level(LogLevel::value::DEBUG){}void buildLoggerType(LoggerType type) { _logger_type = type; }void buildLoggerName(const std::string & name) { _logger_name = name; }void buildLoggerLevel(LogLevel::value level) { _limit_level = level; }void buildFomatter(const std::string &pattern) { _formatter = std::make_shared<Formatter>(pattern); }template<typename SinkType, typename ...Args>void buildSink(Args &&... args){LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);_sinks.push_back(psink);}virtual Logger::ptr build() = 0;protected:LoggerType _logger_type;std::string _logger_name;                  // 日志器名称std::atomic<LogLevel::value> _limit_level; // 日志等级Formatter::ptr _formatter;                 // 格式化std::vector<LogSink::ptr> _sinks;          // 用一个数组来存放日志落地位置};//2.派生出具体的建造者类---局部的日志器建造者&全局的日志器建造者(后边添加了全局单例管理器之后,将日志器添加全局管理)class LocalLoggerBuilder : public LoggerBuilder{public:Logger::ptr build() override{assert(_logger_name.empty() == false); //必须有日志器名称if(_formatter.get() == nullptr){_formatter = std::make_shared<Formatter>();}if(_sinks.empty()){buildSink<StdoutSink>();}if(_logger_type == LoggerType::LOGGER_ASYNC){//返回异步日志器...}//返回同步日志器return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);}};  }#endif

到这本篇博客的内容就到此结束了。
如果觉得本篇博客内容对你有所帮助的话,可以点赞,收藏,顺便关注一下!
如果文章内容有错误,欢迎在评论区指正

在这里插入图片描述

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

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

相关文章

Kubernetes的Sevice管理

服务原理: 所有服务都是根据这个服务衍生或者变化出来,根服务---- 服务感知后端靠标签 slelector 标签选择器 kubectl label pods web1 appweb kubectl cluter-info dump | grep -i service-cluster-ip-range 服务ip取值范围 Service 管理: 创建服务: --- kind: Serv…

React富文本编辑器开发(六)

现在&#xff0c;相关的基础知识我们应该有个大概的了解了&#xff0c;但离我们真正的开发出一个实用型的组件还有一段距离&#xff0c;不过不用担心&#xff0c;我们离目标已经越来越近。 以现在我们所了解的内容而言&#xff0c;或许你发现了一个问题&#xff0c;就是我们的编…

CentOS配网报错:network is unreachable

常用命令&#xff1a; 打开&#xff1a; cd /etc/sysconfig/network-scripts/ 修改&#xff1a; vim ifcfg-ens33 打开修改&#xff1a; vim /etc/sysconfig/network-scripts/ifcfg-ens33 保存&#xff1a; 方法1&#xff1a;ESCZZ&#xff08;Z要大写&#xff09; 方…

Linux:地址空间的转换以及线程的理解和使用

文章目录 线程的理解地址空间的转换问题总结 线程的优点线程的缺点线程的健壮性问题 本篇主要进行对于进程和线程的理解&#xff0c;以及对于线程的一部分使用方法和使用的原理 线程的理解 首先回顾前面一篇的内容中&#xff0c;对于进程的基本认识&#xff1a; 什么是线程&…

【LeetCode:2368. 受限条件下可到达节点的数目 + BFS】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

SpringBoot-yaml语法

1.概念 在Springboot的项目中&#xff0c;配置文件有以下几种格式&#xff1a; Application.propertiesApplication.yamlApplication.yml 其中官方推荐我们使用yaml的格式(因为能表示的数据类型很多样) 2.基本语法 # yaml形式的配置文件# 普通的key-value&#xff08;分号之后…

用numpy搭建自己的神经网络

搭建之前的基础与思考 构建模型的基本思想&#xff1a; 构建深度学习的过程&#xff1a;产生idea&#xff0c;将idea转化成code&#xff0c;最后进行experiment&#xff0c;之后根据结果修改idea&#xff0c;继续idea–>code–>experiment的循环&#xff0c;直到最终训练…

matplotlib条形图

matplotlib条形图 假设你获取到了2017年内地电影票房前20的电影(列表a)和电影票房数据(列表b), 那么如何更加直观的展示该数据? from matplotlib import pyplot as plta ["Wolf Warrior 2", "Fast and Furious 8", "Kung Fu Yoga", "Jo…

线性表——单链表的增删查改

本节复习链表的增删查改 首先&#xff0c; 链表不是连续的&#xff0c; 而是通过指针联系起来的。 如图&#xff1a; 这四个节点不是连续的内存空间&#xff0c; 但是彼此之间使用了一个指针来连接。 这就是链表。 现在我们来实现链表的增删查改。 目录 单链表的全部接口…

位运算---求n的二进制表示中第k位是1还是0 (lowbit)

操作&#xff1a; 先把第k位移到最后一位&#xff08;右边第一位&#xff09; 看个位是1还是0 lowbit(x)&#xff1a;返回x的最右边的1。 原理&#xff1a; 其中 &#xff0c;意思是 是 的补码。 就可以求出最右边的一位1。 应用&#xff1a; 当中 的个数。 int re…

AI-数学-高中-33概率-事件的关系与运算

原作者视频&#xff1a;【概率】【一数辞典】2事件的关系与运算_哔哩哔哩_bilibili 事件&#xff1a; 和/并事件&#xff1b;积/交事件&#xff1b;互诉事件&#xff1b;对立(补集)事件&#xff1b;

【详识JAVA语言】面向对象程序三大特性之二:继承

继承 为什么需要继承 Java中使用类对现实世界中实体来进行描述&#xff0c;类经过实例化之后的产物对象&#xff0c;则可以用来表示现实中的实体&#xff0c;但是 现实世界错综复杂&#xff0c;事物之间可能会存在一些关联&#xff0c;那在设计程序是就需要考虑。 比如&…

04.其他方案

其他方案 1.事务状态表调⽤⽅重试接收⽅幂等 介绍 调⽤⽅维护⼀张事务状态表&#xff08;或者说事务⽇志、⽇志流⽔&#xff09;&#xff0c;在每次调⽤之前&#xff0c;落盘⼀条事务流⽔&#xff0c;⽣成⼀个全局的事务ID 事务开始之前的状态是Begin&#xff0c;全部结束之…

码垛工作站:食品生产企业的转型助推器

在当今高度自动化的工业生产中&#xff0c;码垛工作站的应用正逐渐成为一种趋势。某食品生产企业在面临市场竞争加剧、人工成本上升等多重压力下&#xff0c;决定引入码垛工作站&#xff0c;以期实现生产流程的升级与变革。 一、码垛工作站引入背景 该企业主要从事休闲食品的…

【贪心算法】Leetcode 455.分发饼干 376. 摆动序列 53. 最大子数组和

【贪心算法】Leetcode 455 分发饼干 376. 摆动序列【规律很多】53. 最大子数组和 455 分发饼干局部最优推全局最优&#xff1a;尽量用大饼干去满足大胃口的小朋友 376. 摆动序列【规律很多】思想&#xff1a;注意考虑一个坡度留首尾两个点、平坡、首尾 53. 最大子数组和【好思想…

15.网络游戏逆向分析与漏洞攻防-网络通信数据包分析工具-发送通信数据包至分析工具

上一个内容&#xff1a;14.数据包分析工具界面与通信设计 码云地址&#xff08;master 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/titan 码云版本号&#xff1a;2d6491e3c51a1a7ab4da0ee6dc4cf566a80fd6e1 代码下载地址&#xff0c;在 titan 目录下&…

模版进阶C++

非类型模版 之前我们写的模版都是在不知道模版&#xff08;类&#xff09;中有的变量的类型是什么的时候&#xff0c;我们先用模版参数定义&#xff0c;当类实例化的时候在传参确认 非类型模版&#xff1a;模版参数定义的时候也可以定义整型类型&#xff08;c20之后才支持其…

奇点云:SAFe框架下,我们对平台软件工程生产线做了4项改造

导读&#xff1a; 客户规模扩大&#xff0c;如何保证大数据软件产品和服务质量始终如一&#xff1f;几乎所有成长中的软件厂商&#xff0c;尤其是需要通过私有化部署交付的厂商&#xff0c;都会面临这个问题。正如《人月神话》中多次表明的&#xff0c;单纯地增加人手、扩大团队…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的植物病害检测系统(Python+PySide6界面+训练代码)

摘要&#xff1a;开发高效的植物病害检测系统对于提升农业生产效率和作物健康管理意义重大。本篇博客详细阐述了如何运用深度学习技术构建一个植物病害检测系统&#xff0c;并提供了完整的实现代码。该系统基于先进的YOLOv8算法&#xff0c;对YOLOv7、YOLOv6、YOLOv5进行了性能…

考研数学——高数:微分方程

一、一阶线性微分方程 两种形式&#xff1a; 非齐次&#xff1a; 齐次&#xff1a; 推导过程 推导公式的过程一般由特殊到一般&#xff1a;所以先求解齐次方程的解 &#xff08;然后对等式两边同时积分&#xff09; 再来求非齐次方程的解&#xff0c;由…