📟作者主頁:慢熱的陜西人
🌴專欄鏈接: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
到這本篇博客的內容就到此結束了。
如果覺得本篇博客內容對你有所幫助的話,可以點贊,收藏,順便關注一下!
如果文章內容有錯誤,歡迎在評論區指正