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

news2024/12/23 19:14:03

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

🌴专栏链接: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.coloradmin.cn/o/1487283.html

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

相关文章

“智农”-农业物联网可视化

大棚可视化|设施农业可视化|农业元宇宙|农业数字孪生|大棚物联网|大棚数字孪生|农业一体化管控平台|智慧农业可视化|智农|农业物联网可视化|农业物联网数字孪生|智慧农业|大棚三维可视化|智慧大棚可视化|智慧大棚|农业智慧园区|数字农业|数字大棚|农业大脑|智慧牧业数字孪生|智…

072:vue+cesium 实现下雪效果

第072个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中实现下雪效果,这里使用着色器来实现实例特效。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共120行)着色代码实现心得:专栏目标示例效果

2022NOC大赛原创未来赛道小学低年级组图形化真题加解析

这篇文档是一份未来小学低年级组图形化真题加解析,主要面向小学生进行考试。考试内容主要包括图形化思维、数学运算和阅读理解等方面。 图形化思维是近年来数学教育中备受关注的领域,通过将抽象的概念转化为具体的形象,帮助学习者更好地理解和掌握数学知识。因此,在这个考试…

STM32-BKP备份寄存器和RTC时钟

BKP介绍 BKP(Bckup Registers&#xff09;备份寄存器 备份寄存器是42个16位的寄存器&#xff0c;可用来存储84个字节的用户应用程序数据。他们处在备份域里&#xff0c;当VDD电源被切断&#xff0c;他们仍然由VBAT&#xff08;备用电池电源&#xff09;维持供电。当系统在待机…

011集——vba获取CAD图中图元类名objectname

在CAD中&#xff0c;通过快捷键PL&#xff08;即POLYLINE命令&#xff09;绘制的线属于AcDbPolyline。AcDbPolyline也被称为LWPOLYLINE&#xff0c;即简单Polyline&#xff0c;它所包含的对象在本身内部。 此外&#xff0c;CAD中还有另一种二维多段线对象&#xff0c;称为AcDb2…

Vue开发实例(十一)用户列表的实现与操作

用户列表的实现与操作 一、创建用户页面和路由二、表格优化1、表头自定义2、表格滚动3、加入数据索引4、利用插槽自定义显示 三、功能1、查询功能3、增加4、删除5、修改 一、创建用户页面和路由 创建用户页面 在 src/components/Main 下创建文件夹user&#xff0c;创建文件Us…

苍穹外卖Day05——总结5

前期文章 文章标题地址苍穹外卖Day01——总结1https://lushimeng.blog.csdn.net/article/details/135466359苍穹外卖Day01——解决总结1中存在的问题https://lushimeng.blog.csdn.net/article/details/135473412苍穹外卖Day02——总结2https://lushimeng.blog.csdn.net/articl…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于条件风险价值的虚拟电厂参与能量及备用市场的双层随机优化》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 这篇文章的标题涉及到以下几个关键点…

【二叉树的最近公共祖先】【后序遍历】Leetcode 236. 二叉树的最近公共祖先

【二叉树的最近公共祖先】【后序遍历】Leetcode 236. 二叉树的最近公共祖先 解法1 涉及到结果向上返回就要用后序遍历解法2 自己写的方法 后序遍历 ---------------&#x1f388;&#x1f388;236. 二叉树的最近公共祖先 题目链接&#x1f388;&#x1f388;-----------------…

【kubernetes】关于k8s集群如何将pod调度到指定node节点?

目录 一、k8s的watch机制 二、scheduler的调度策略 Predicate&#xff08;预选策略&#xff09; 常见算法&#xff1a; priorities&#xff08;优选策略&#xff09;常见的算法有&#xff1a; 三、k8s的标签管理之增删改查 四、k8s的将pod调度到指定node的方法 方案一&am…

20个 K8S集群常见问题总结,建议收藏

问题1&#xff1a;K8S集群服务访问失败&#xff1f; 原因分析&#xff1a;证书不能被识别&#xff0c;其原因为&#xff1a;自定义证书&#xff0c;过期等。 解决方法&#xff1a;更新证书即可。 问题2&#xff1a;K8S集群服务访问失败&#xff1f; curl: (7) Failed connec…

YOLOv9改进 | 基础篇 | 提供YOLOv9全系列支持V9n、V9s、V9m、V9l、V9x的修改方式(全网独家首发)

一、本文介绍 大家好&#xff0c;本文给大家带来的是2024年2月21日全新发布的SOTA模型YOLOv9的补全教程&#xff08;算是一种补全吧我个人认为&#xff09;&#xff0c;了解V7的读者都知道V7系列是不支持模型深度和宽度的修改的也就是没有办法像YOLOv8那样有多个版本&#xff…

IOC中Bean的生命周期

生命周期的各个阶段&#xff1a; 可以分为三个阶段&#xff1a;产生-使用-销毁 又可以分四个阶段&#xff1a;四个阶段 实例化 ->属性注入->初始化 ->销毁 实例化后到使用的初始化过程&#xff1a; 属性赋值 ->处理各种Aware接口->实现BeanPostProcessor的b…

【大厂AI课学习笔记NO.63】模型的维护

说是模型的维护&#xff0c;其实这堂课都是在讲“在工业环境中开发和部署机器学习模型的流程”。 上图来自于我的笔记思维脑图&#xff0c;已经上传&#xff0c;要链接的访问的主页查看资源。 一路走来&#xff0c;我们学习了数据管理、模型学习、模型验证、模型部署等重要的步…

js中Generator函数详解

定义&#xff1a; promise是为了解决回调地狱的难题出现的&#xff0c;那么 Generator 就是为了解决异步问题而出现的。 普通函数&#xff0c;如果调用它会立即执行完毕&#xff1b;Generator 函数&#xff0c;它可以暂停&#xff0c;不一定马上把函数体中的所有代码执行完毕…

鸿蒙App开发新思路:小程序转App

国家与国家之间错综复杂&#xff0c;在谷歌的安卓操作系统“断供”后&#xff0c;鸿蒙系统的市场化&独立化的道路便显而易见了。 2024年1月18日&#xff0c;华为宣布&#xff0c;不再兼容安卓的“纯血鸿蒙”--HarmonyOS NEXT鸿蒙星河版最终面世&#xff0c;并与2024年Q4正…

自己本地模拟内存数据库增删改查

目录 学习初衷准备代码实现结果感谢阅读 学习初衷 用于满足自己的测试要求&#xff0c;不连接数据库&#xff0c;也不在意数据丢失 准备 maven依赖 org.springframework.boot spring-boot-starter-test test 代码实现 内存数据库&#xff08;InMemoryDatabase&#xff0…

AmzTrends x TiDB Serverless:通过云原生改造实现全局成本降低 80%

本文介绍了厦门笛卡尔数据&#xff08;AmzTrends&#xff09;在面临数据存储挑战时&#xff0c;选择将其数据分析服务迁移到 TiDB Serverless 的思路和实践。通过全托管的数据库服务&#xff0c;AmzTrends 实现了全局成本降低 80% 的效果&#xff0c;同时也充分展示了 TiDB Ser…

【活动】金三银四,前端工程师如何把握求职黄金期

随着春意盎然的气息弥漫大地&#xff0c;程序员群体中也迎来了一年一度的“金三银四”求职热潮。这个时间段对于广大前端工程师而言&#xff0c;不仅象征着生机勃发的新起点&#xff0c;更是他们职业生涯中至关重要的转折点。众多知名公司在这一时期大规模开启招聘通道&#xf…

Java面试题总结200道(二)

26、简述Spring中Bean的生命周期&#xff1f; 在原生的java环境中&#xff0c;一个新的对象的产生是我们用new()的方式产生出来的。在Spring的IOC容器中&#xff0c;将这一部分的工作帮我们完成了(Bean对象的管理)。既然是对象&#xff0c;就存在生命周期&#xff0c;也就是作用…