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.pswp.cn/news/717547.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/717547.shtml
英文地址,請注明出處:http://en.pswp.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; 方…

LabelImg官方文檔摘錄

LabelImg官方文檔&#xff1a;https://github.com/HumanSignal/labelImg 注釋&#xff08;annotation&#xff09;以 PASCAL VOC 格式保存為 XML 文件&#xff0c;這是ImageNet使用的格式。此外&#xff0c;它還支持 YOLO 和 CreateML 格式。 安裝 使用CSDN博主打包的程序&a…

Linux:地址空間的轉換以及線程的理解和使用

文章目錄 線程的理解地址空間的轉換問題總結 線程的優點線程的缺點線程的健壯性問題 本篇主要進行對于進程和線程的理解&#xff0c;以及對于線程的一部分使用方法和使用的原理 線程的理解 首先回顧前面一篇的內容中&#xff0c;對于進程的基本認識&#xff1a; 什么是線程&…

OWASP TOP 10解析:構建堅不可摧的Web應用安全防線

當涉及到Web應用程序安全的話題時&#xff0c;OWASP&#xff08;開放式Web應用程序安全項目&#xff09;的TOP 10是一個不可忽視的參考點。OWASP TOP 10列舉了當前Web應用程序中最嚴重的安全風險&#xff0c;幫助開發人員、測試人員和安全專業人員更好地理解并針對這些風險采取…

【LeetCode:2368. 受限條件下可到達節點的數目 + BFS】

&#x1f680; 算法題 &#x1f680; &#x1f332; 算法刷題專欄 | 面試必備算法 | 面試高頻算法 &#x1f340; &#x1f332; 越難的東西,越要努力堅持&#xff0c;因為它具有很高的價值&#xff0c;算法就是這樣? &#x1f332; 作者簡介&#xff1a;碩風和煒&#xff0c;…

Mybatis實戰(1)

mybatis-pageHelper 1&#xff0c;添加依賴&#xff1a; <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><!--pag…

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…

【LiveData】LiveData轉換及操作符分析

使用示例 LiveData操作符可以將一個LiveData轉換為另一個LiveData 當源LiveData發生變更時&#xff0c;會自動通知目標LiveData val srcLiveData : LiveData<T>val dstLiveData : LiveData<R>dstLiveData srcLiveData.distinctUntilChanged().switchMap{returnsw…

線性表——單鏈表的增刪查改

本節復習鏈表的增刪查改 首先&#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;全部結束之…

Go語言進階篇——文件

文件的打開 文件的常見的兩種打開方式是基于os包所提供的兩個函數: func Open(name string) (*File,error) func OpenFile(name string flag int perm FileMode) (*File,error)相對于前者&#xff0c;OpenFile可以提供更加細致的操作&#xff0c;而前者就是對后者的一個簡單封…

碼垛工作站:食品生產企業的轉型助推器

在當今高度自動化的工業生產中&#xff0c;碼垛工作站的應用正逐漸成為一種趨勢。某食品生產企業在面臨市場競爭加劇、人工成本上升等多重壓力下&#xff0c;決定引入碼垛工作站&#xff0c;以期實現生產流程的升級與變革。 一、碼垛工作站引入背景 該企業主要從事休閑食品的…

Android 中的 LinearLayout 布局

在 Android 開發中&#xff0c;布局是至關重要的一部分&#xff0c;它決定了應用程序的界面結構和用戶體驗。LinearLayout 是 Android 中最常用的布局之一&#xff0c;它以線性方式排列子視圖&#xff0c;可以垂直或水平布局。在這篇博客中&#xff0c;我們將深入了解 LinearLa…