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.hqwc.cn/news/508335.html

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

相关文章

Unreal触屏和鼠标控制旋转冲突问题

Unreal触屏和鼠标控制旋转冲突问题 鼠标控制摄像机旋转添加Input轴计算旋转角度通过轴事件控制旋转 问题和原因问题原因 解决办法增加触摸控制旋转代码触屏操作下屏蔽鼠标轴响应事件 鼠标控制摄像机旋转 通过Mouse X和Mouse Y控制摄像机旋转。 添加Input轴 计算旋转角度 通过…

外贸网站模板建站

测绘检测wordpress外贸主题 简洁实用的wordpress外贸主题&#xff0c;适合做测绘检测仪器设备的外贸公司使用。 https://www.jianzhanpress.com/?p5337 白马非马衣服WordPress外贸建站模板 白马非马服装行业wordpress外贸建站模板&#xff0c;适用于时间服装企业的官方网站…

利用redis实现秒杀功能

6、秒杀优化 这个是 图灵 的redis实战里面的一个案例 6.1 秒杀优化-异步秒杀思路 我们来回顾一下下单流程 当用户发起请求&#xff0c;此时会请求nginx&#xff0c;nginx会访问到tomcat&#xff0c;而tomcat中的程序&#xff0c;会进行串行操作&#xff0c;分成如下几个步骤…

求Sn=a+aa+aaa+aaaa+aaaaa的前n项之和

求Snaaaaaaaaaaaaaaa的前5项之和&#xff0c;其中a是一个数字&#xff0c; 例如&#xff1a;222222222222222 int main() {int a;scanf("%d", &a);int n;scanf("%d", &n);int sum 0;int tmp 0;for (int i 0; i < n; i){tmp tmp * 10 a;sum…

Wikidata数据结构及本地部署——支持SPARQL查询

Wikidata 本地部署 Github&#xff1a;https://github.com/NP-NET-research/wdel 欢迎来 star && fork && issue ~~ 有问题可以通过邮箱&#xff1a;xuzhengfei-emailqq.com 联系我~~ 文章目录 Wikidata 本地部署1、Wikidata 简介1.1 Wikidata 数据结构1.2 …

Javaweb之SpringBootWeb案例之自动配置的@Conditional源码的详细解析

3.2.3.2 Conditional 我们在跟踪SpringBoot自动配置的源码的时候&#xff0c;在自动配置类声明bean的时候&#xff0c;除了在方法上加了一个Bean注解以外&#xff0c;还会经常用到一个注解&#xff0c;就是以Conditional开头的这一类的注解。以Conditional开头的这些注解都是条…

【数据结构】B树

1 B树介绍 B树&#xff08;英语&#xff1a;B-tree&#xff09;&#xff0c;是一种在计算机科学自平衡的树&#xff0c;能够保持数据有序。这种数据结构能够让查找数据、顺序访问、插入数据及删除的动作&#xff0c;都在对数时间内完成。B树&#xff0c;概括来说是一个一般化的…

黑科技工具盒源码 好用的手机工具盒iAPP源码

全新推出&#xff01;多功能工具箱&#xff1a;一款实用的手机工具集&#xff0c;提供丰富的免费小工具&#xff0c;操作简便。目前包含六项黑科技功能&#xff0c;分别为QQ云端、短信测压、Q绑查询、照妖镜、chatgpt、网页一键打包APP。工具箱体积小巧&#xff0c;不占内存&am…

u盘打不开提示需要格式化,怎么恢复数据?

U盘是不少办公族和学生党常用的文件存储工具&#xff0c;当我们的U盘提示需要格式化时&#xff0c;往往意味着U盘的文件系统可能出现了问题。这可能是由于病毒感染、不当操作、硬件故障等原因引起的。但在此之前U盘中存储的数据对我们可能非常重要。那么如何在不丢失数据的情况…

excel统计分析——拉丁方设计

参考资料&#xff1a;生物统计学 拉丁方设计也是随机区组设计&#xff0c;是对随机区组设计的一种改进。它在行的方向和列的方向都可以看成区组&#xff0c;因此能实现双向误差的控制。在一般的试验设计中&#xff0c;拉丁方常被看作双区组设计&#xff0c;用于提高发现处理效应…

技术总结: PPT绘图

目录 写在前面参考文档技巧总结PPT中元素的连接立方体调整厚度调整图形中的文本3D 图片调整渐变中的颜色 写在前面 能绘制好一个好看的示意图非常重要, 在科研和工作中好的示意图能精准表达出自己的想法, 减少沟通的成本, 可视化的呈现也可以加强自身对系统的理解, 时间很久后…

dvwa靶场xss通关

原理 XSS漏洞是攻击者将恶意代码注入到合法网页中&#xff0c;当用户浏览该页面时&#xff0c;恶意代码会被执行&#xff0c;从而获取用户敏感信息或进行其他攻击。 形成原因 网站对用户输入数据的过滤不严格或不完备&#xff0c;攻击者可以根据这个漏洞向网站提交恶意代码&am…