欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 产业 > 日志与策略模式

日志与策略模式

2025/7/23 20:20:03 来源:https://blog.csdn.net/2302_81171591/article/details/148366953  浏览:    关键词:日志与策略模式

什么是设计模式


IT行业这么火, 涌入的人很多. 俗话说林子大了啥鸟都有. 大佬和菜鸡们两极分化的越来越严重. 为了让菜鸡们不太拖大佬的后腿, 于是大佬们针对一些经典的常见的场景, 给定了一些对应的解决方案, 这个就是 设计模式


日志认识


计算机中的日志是记录系统和软件运行中发发事件的文件,主要作用是监控运行状态、记录异常信
息,帮助快速定位问题并支持程序员进行问题修复。它是系统维护、故障排查和安全管理的重要工
具。

日志格式以下几个指标是必须得有的

  • 时间戳
  • 日志等级
  • 日志内容

以下几个指标是可选的

  • 文件名行号
  • 进程,线程相关id信息等

日志有现成的解决方案,如:spdlog、glog、Boost.Log、Log4cxx等等,我们依旧采用自定义日志的方式。
这里我们采用设计模式-策略模式来进行日志的设计,我们想要的日志格式如下:

[可读性很好的时间] [⽇志等级] [进程pid] [打印对应⽇志的⽂件名][⾏号] - 消息内容,⽀持可
变参数
[2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [16] - hello world
[2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [17] - hello world
[2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [18] - hello world
[2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [20] - hello world
[2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [21] - hello world
[2024-08-04 12:27:03] [WARNING] [202938] [main.cc] [23] - hello world

日志功能:

  1. 形成完整日志
  2. 刷新到目标文件(显示器,指定文件打印日志)

多态实现两种策略的实现

Log.hpp

#ifndef __LOG_HPP__
#define __LOG_HPP__#include <iostream>
#include <string>
#include "Mutex.hpp"
#include <filesystem>
#include <fstream>
namespace LogModule
{const std::string sep = "\r\n";using namespace MutexModule;// 2.刷新策略class LogStrategy{public:~LogStrategy() = default;virtual void SyncLog(const std::string &message) = 0;};// 显示器刷新日志的策略class ConsoleLogStrategy : public LogStrategy{public:ConsoleLogStrategy() {}~ConsoleLogStrategy() {}void SyncLog(const std::string &message) override{LockGuard lockguard(_mutex);std::cout << message << sep;}private:Mutex _mutex;};// 缺省文件路径以及文件本身const std::string defaultpath = "./log";const std::string defaultfile = "my.log";// 文件刷新日志的策略class FileLogStrategy : public LogStrategy{public:FileLogStrategy(const std::string &path = defaultpath, const std::string &file = defaultfile): _path(path), _file(file){LockGuard lockguard(_mutex);if (std::filesystem::exists(_path)) // 判断路径是否存在{return;}try{std::filesystem::create_directories(_path);}catch (const std::filesystem::filesystem_error &e){std::cerr << e.what() << '\n';}}void SyncLog(const std::string &message) override{LockGuard lockguard(_mutex);std::string filename = _path + (_path.back() == '/' ? "" : "/") + _file;std::ofstream out(filename, std::ios::app); // 追加写入if (!out.is_open()){return;}out << message << sep;out.close();}~FileLogStrategy() {}private:Mutex _mutex;std::string _path; // 日志文件的路径std::string _file; // 要打印的日志文件};}#endif

 Main.cc

#include <iostream>
#include "Log.hpp"
#include <memory>using namespace LogModule;
int main()
{   // 显示器刷新std::unique_ptr<LogStrategy> strategy1 = std::make_unique<ConsoleLogStrategy>(); // c++14strategy1->SyncLog("hello log1!");// 指定文件刷新std::unique_ptr<LogStrategy> strategy2 = std::make_unique<FileLogStrategy>(); // c++14strategy2->SyncLog("hello log2!");return 0;
}

 形成完整日志

Log.hpp

#ifndef __LOG_HPP__
#define __LOG_HPP__#include <iostream>
#include <string>
#include "Mutex.hpp"
#include <filesystem>
#include <fstream>
#include <memory>
#include <unistd.h>
#include <sstream>namespace LogModule
{const std::string sep = "\r\n";using namespace MutexModule;// 2.刷新策略class LogStrategy{public:~LogStrategy() = default;virtual void SyncLog(const std::string &message) = 0;};// 显示器刷新日志的策略class ConsoleLogStrategy : public LogStrategy{public:ConsoleLogStrategy() {}~ConsoleLogStrategy() {}void SyncLog(const std::string &message) override{LockGuard lockguard(_mutex);std::cout << message << sep;}private:Mutex _mutex;};// 缺省文件路径以及文件本身const std::string defaultpath = "./log";const std::string defaultfile = "my.log";// 文件刷新日志的策略class FileLogStrategy : public LogStrategy{public:FileLogStrategy(const std::string &path = defaultpath, const std::string &file = defaultfile): _path(path), _file(file){LockGuard lockguard(_mutex);if (std::filesystem::exists(_path)) // 判断路径是否存在{return;}try{std::filesystem::create_directories(_path);}catch (const std::filesystem::filesystem_error &e){std::cerr << e.what() << '\n';}}void SyncLog(const std::string &message) override{LockGuard lockguard(_mutex);std::string filename = _path + (_path.back() == '/' ? "" : "/") + _file;std::ofstream out(filename, std::ios::app); // 追加写入if (!out.is_open()){return;}out << message << sep;out.close();}~FileLogStrategy() {}private:Mutex _mutex;std::string _path; // 日志文件的路径std::string _file; // 要打印的日志文件};// 形成日志等级enum class Loglevel{DEBUG,INIF,WARNING,ERROR,FATAL};std::string Level2Str(Loglevel level){switch (level){case Loglevel::DEBUG:return "DEBUG";case Loglevel::INIF:return "INIF";case Loglevel::WARNING:return "WARNING";case Loglevel::ERROR:return "ERROR";case Loglevel::FATAL:return "FATAL";default:return "UNKNOWN";}}std::string GetTimeStamp(){return "XXX";}class Logger{public:Logger(){EnableConsoleLogStrategy();}// 选择某种策略// 1.文件void EnableFileLogStrategy(){_ffush_strategy = std::make_unique<FileLogStrategy>();}// 显示器void EnableConsoleLogStrategy(){_ffush_strategy = std::make_unique<ConsoleLogStrategy>();}// 表示的是未来的一条日志class LogMessage{public:LogMessage(Loglevel &level, std::string &src_name, int line_number, Logger &logger): _curr_time(GetTimeStamp()), _level(level), _pid(getpid()), _src_name(src_name), _line_number(line_number), _logger(logger){// 合并左半部分std::stringstream ss;ss << "[" << _curr_time << "] "<< "[" << Level2Str(_level) << "] "<< "[" << _pid << "] "<< "[" << _src_name << "] "<< "[" << _line_number << "] "<< "- ";_loginfo = ss.str();}template <typename T>LogMessage &operator<<(const T &info){// 右半部分,可变std::stringstream ss;ss << info;_loginfo += ss.str();return *this;}~LogMessage(){if (_logger._ffush_strategy){_logger._ffush_strategy->SyncLog(_loginfo);}}private:std::string _curr_time; // 日志时间Loglevel _level;        // 日志状态pid_t _pid;             // 进程pidstd::string _src_name;  // 文件名称int _line_number;       // 对应的行号std::string _loginfo;   // 合并之后的一条完整信息Logger &_logger;};LogMessage operator()(Loglevel level, std::string src_name, int line_number){return LogMessage(level, src_name, line_number, *this);}~Logger() {}private:std::unique_ptr<LogStrategy> _ffush_strategy;};
}#endif

Main.cc

#include <iostream>
#include "Log.hpp"
#include <memory>using namespace LogModule;
int main()
{Logger log;//显示器打印log(Loglevel::DEBUG,"Main.cc",10)<<"hello log!";log(Loglevel::DEBUG,"Main.cc",10)<<"hello log!";log(Loglevel::DEBUG,"Main.cc",10)<<"hello log!";log(Loglevel::DEBUG,"Main.cc",10)<<"hello log!";log(Loglevel::DEBUG,"Main.cc",10)<<"hello log!";log(Loglevel::DEBUG,"Main.cc",10)<<"hello log!";//日志文件打印log.EnableFileLogStrategy();log(Loglevel::DEBUG,"Main.cc",10)<<"hello log!";log(Loglevel::DEBUG,"Main.cc",10)<<"hello log!";log(Loglevel::DEBUG,"Main.cc",10)<<"hello log!";log(Loglevel::DEBUG,"Main.cc",10)<<"hello log!";log(Loglevel::DEBUG,"Main.cc",10)<<"hello log!";log(Loglevel::DEBUG,"Main.cc",10)<<"hello log!";return 0;
}

 

使用宏简化代码

Log.hpp

#ifndef __LOG_HPP__
#define __LOG_HPP__#include <iostream>
#include <string>
#include "Mutex.hpp"
#include <filesystem>
#include <fstream>
#include <memory>
#include <unistd.h>
#include <sstream>namespace LogModule
{const std::string sep = "\r\n";using namespace MutexModule;// 2.刷新策略class LogStrategy{public:~LogStrategy() = default;virtual void SyncLog(const std::string &message) = 0;};// 显示器刷新日志的策略class ConsoleLogStrategy : public LogStrategy{public:ConsoleLogStrategy() {}~ConsoleLogStrategy() {}void SyncLog(const std::string &message) override{LockGuard lockguard(_mutex);std::cout << message << sep;}private:Mutex _mutex;};// 缺省文件路径以及文件本身const std::string defaultpath = "./log";const std::string defaultfile = "my.log";// 文件刷新日志的策略class FileLogStrategy : public LogStrategy{public:FileLogStrategy(const std::string &path = defaultpath, const std::string &file = defaultfile): _path(path), _file(file){LockGuard lockguard(_mutex);if (std::filesystem::exists(_path)) // 判断路径是否存在{return;}try{std::filesystem::create_directories(_path);}catch (const std::filesystem::filesystem_error &e){std::cerr << e.what() << '\n';}}void SyncLog(const std::string &message) override{LockGuard lockguard(_mutex);std::string filename = _path + (_path.back() == '/' ? "" : "/") + _file;std::ofstream out(filename, std::ios::app); // 追加写入if (!out.is_open()){return;}out << message << sep;out.close();}~FileLogStrategy() {}private:Mutex _mutex;std::string _path; // 日志文件的路径std::string _file; // 要打印的日志文件};// 形成日志等级enum class Loglevel{DEBUG,INIF,WARNING,ERROR,FATAL};std::string Level2Str(Loglevel level){switch (level){case Loglevel::DEBUG:return "DEBUG";case Loglevel::INIF:return "INIF";case Loglevel::WARNING:return "WARNING";case Loglevel::ERROR:return "ERROR";case Loglevel::FATAL:return "FATAL";default:return "UNKNOWN";}}std::string GetTimeStamp(){return "XXX";}class Logger{public:Logger(){EnableConsoleLogStrategy();}// 选择某种策略// 1.文件void EnableFileLogStrategy(){_ffush_strategy = std::make_unique<FileLogStrategy>();}// 显示器void EnableConsoleLogStrategy(){_ffush_strategy = std::make_unique<ConsoleLogStrategy>();}// 表示的是未来的一条日志class LogMessage{public:LogMessage(Loglevel &level, std::string &src_name, int line_number, Logger &logger): _curr_time(GetTimeStamp()), _level(level), _pid(getpid()), _src_name(src_name), _line_number(line_number), _logger(logger){// 合并左半部分std::stringstream ss;ss << "[" << _curr_time << "] "<< "[" << Level2Str(_level) << "] "<< "[" << _pid << "] "<< "[" << _src_name << "] "<< "[" << _line_number << "] "<< "- ";_loginfo = ss.str();}template <typename T>LogMessage &operator<<(const T &info){// 右半部分,可变std::stringstream ss;ss << info;_loginfo += ss.str();return *this;}~LogMessage(){if (_logger._ffush_strategy){_logger._ffush_strategy->SyncLog(_loginfo);}}private:std::string _curr_time; // 日志时间Loglevel _level;        // 日志状态pid_t _pid;             // 进程pidstd::string _src_name;  // 文件名称int _line_number;       // 对应的行号std::string _loginfo;   // 合并之后的一条完整信息Logger &_logger;};LogMessage operator()(Loglevel level, std::string src_name, int line_number){return LogMessage(level, src_name, line_number, *this);}~Logger() {}private:std::unique_ptr<LogStrategy> _ffush_strategy;};//全局日志对象Logger logger;//使用宏,简化用户操作,获取文件名和行号// __FILE__  一个宏,替换完成后目标文件的文件名// __LINE__  一个宏,替换完成后目标文件对应的行号#define LOG(level) logger(level,__FILE__,__LINE__) #define Enable_Console_Log_Strategy() logger.EnableConsoleLogStrategy()#define Enable_File_Log_Strategy()    logger.EnableFileLogStrategy()}#endif

 Main.cc

#include <iostream>
#include "Log.hpp"
#include <memory>using namespace LogModule;
int main()
{Logger log;//显示器打印Enable_Console_Log_Strategy();LOG(Loglevel::DEBUG)<<"hello"<<" log!";LOG(Loglevel::DEBUG)<<"hello"<<" log!";LOG(Loglevel::DEBUG)<<"hello"<<" log!";//日志文件打印Enable_File_Log_Strategy();LOG(Loglevel::DEBUG)<<"hello"<<" log!";LOG(Loglevel::DEBUG)<<"hello"<<" log!";LOG(Loglevel::DEBUG)<<"hello"<<" log!";return 0;
}

 

 补上时间,收工

完整日志实现代码

Log.hpp

#ifndef __LOG_HPP__
#define __LOG_HPP__#include <iostream>
#include <string>
#include "Mutex.hpp"
#include <filesystem>
#include <fstream>
#include <memory>
#include <unistd.h>
#include <sstream>
#include<ctime>namespace LogModule
{const std::string sep = "\r\n";using namespace MutexModule;// 2.刷新策略class LogStrategy{public:~LogStrategy() = default;virtual void SyncLog(const std::string &message) = 0;};// 显示器刷新日志的策略class ConsoleLogStrategy : public LogStrategy{public:ConsoleLogStrategy() {}~ConsoleLogStrategy() {}void SyncLog(const std::string &message) override{LockGuard lockguard(_mutex);std::cout << message << sep;}private:Mutex _mutex;};// 缺省文件路径以及文件本身const std::string defaultpath = "./log";const std::string defaultfile = "my.log";// 文件刷新日志的策略class FileLogStrategy : public LogStrategy{public:FileLogStrategy(const std::string &path = defaultpath, const std::string &file = defaultfile): _path(path), _file(file){LockGuard lockguard(_mutex);if (std::filesystem::exists(_path)) // 判断路径是否存在{return;}try{std::filesystem::create_directories(_path);}catch (const std::filesystem::filesystem_error &e){std::cerr << e.what() << '\n';}}void SyncLog(const std::string &message) override{LockGuard lockguard(_mutex);std::string filename = _path + (_path.back() == '/' ? "" : "/") + _file;std::ofstream out(filename, std::ios::app); // 追加写入if (!out.is_open()){return;}out << message << sep;out.close();}~FileLogStrategy() {}private:Mutex _mutex;std::string _path; // 日志文件的路径std::string _file; // 要打印的日志文件};// 形成日志等级enum class Loglevel{DEBUG,INIF,WARNING,ERROR,FATAL};std::string Level2Str(Loglevel level){switch (level){case Loglevel::DEBUG:return "DEBUG";case Loglevel::INIF:return "INIF";case Loglevel::WARNING:return "WARNING";case Loglevel::ERROR:return "ERROR";case Loglevel::FATAL:return "FATAL";default:return "UNKNOWN";}}std::string GetTimeStamp(){time_t cuur =time(nullptr);struct tm curr_tm;localtime_r(&cuur,&curr_tm);char buffer[128];snprintf(buffer,sizeof(buffer),"%4d-%02d-%02d %02d:%02d:%02d",curr_tm.tm_year+1900,curr_tm.tm_mon+1,curr_tm.tm_mday,curr_tm.tm_hour,curr_tm.tm_min,curr_tm.tm_sec);return buffer;}class Logger{public:Logger(){EnableConsoleLogStrategy();}// 选择某种策略// 1.文件void EnableFileLogStrategy(){_ffush_strategy = std::make_unique<FileLogStrategy>();}// 显示器void EnableConsoleLogStrategy(){_ffush_strategy = std::make_unique<ConsoleLogStrategy>();}// 表示的是未来的一条日志class LogMessage{public:LogMessage(Loglevel &level, std::string &src_name, int line_number, Logger &logger): _curr_time(GetTimeStamp()), _level(level), _pid(getpid()), _src_name(src_name), _line_number(line_number), _logger(logger){// 合并左半部分std::stringstream ss;ss << "[" << _curr_time << "] "<< "[" << Level2Str(_level) << "] "<< "[" << _pid << "] "<< "[" << _src_name << "] "<< "[" << _line_number << "] "<< "- ";_loginfo = ss.str();}template <typename T>LogMessage &operator<<(const T &info){// 右半部分,可变std::stringstream ss;ss << info;_loginfo += ss.str();return *this;}~LogMessage(){if (_logger._ffush_strategy){_logger._ffush_strategy->SyncLog(_loginfo);}}private:std::string _curr_time; // 日志时间Loglevel _level;        // 日志状态pid_t _pid;             // 进程pidstd::string _src_name;  // 文件名称int _line_number;       // 对应的行号std::string _loginfo;   // 合并之后的一条完整信息Logger &_logger;};LogMessage operator()(Loglevel level, std::string src_name, int line_number){return LogMessage(level, src_name, line_number, *this);}~Logger() {}private:std::unique_ptr<LogStrategy> _ffush_strategy;};//全局日志对象Logger logger;//使用宏,简化用户操作,获取文件名和行号// __FILE__  一个宏,替换完成后目标文件的文件名// __LINE__  一个宏,替换完成后目标文件对应的行号#define LOG(level) logger(level,__FILE__,__LINE__) #define Enable_Console_Log_Strategy() logger.EnableConsoleLogStrategy()#define Enable_File_Log_Strategy()    logger.EnableFileLogStrategy()}#endif

Mutex.hpp

#include <pthread.h>
#include <iostream>
namespace MutexModule
{class Mutex{public:Mutex(){pthread_mutex_init(&_mutex, nullptr);}void Lock(){int n = pthread_mutex_lock(&_mutex);(void)n;}void Unlock(){int n = pthread_mutex_unlock(&_mutex);(void)n;}~Mutex(){pthread_mutex_destroy(&_mutex);}pthread_mutex_t *get(){return &_mutex;}private:pthread_mutex_t _mutex;};class LockGuard{public:LockGuard(Mutex &mutex):_mutex(mutex){_mutex.Lock();}~LockGuard(){_mutex.Unlock();}private:Mutex &_mutex;};
}

Main.cc

#include <iostream>
#include "Log.hpp"
#include <memory>using namespace LogModule;
int main()
{Logger log;//显示器打印Enable_Console_Log_Strategy();LOG(Loglevel::DEBUG)<<"hello"<<" log!";LOG(Loglevel::DEBUG)<<"hello"<<" log!";LOG(Loglevel::DEBUG)<<"hello"<<" log!";//日志文件打印Enable_File_Log_Strategy();LOG(Loglevel::DEBUG)<<"hello"<<" log!";LOG(Loglevel::DEBUG)<<"hello"<<" log!";LOG(Loglevel::DEBUG)<<"hello"<<" log!";return 0;
}

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词