日志與策略模式

什么是設計模式

IT?業 ,為了讓 菜雞們不太拖?佬的后腿, 于是?佬們針對?些經典的常?的場景, 給定了?些對應的解決?案, 這個就是? 設計模式?

日志認識

計算機中的?志是記錄系統和軟件運?中發?事件的?件,主要作?是監控運?狀態、記錄異常信 息,幫助快速定位問題并?持程序員進?問題修復。它是系統維護、故障排查和安全管理的重要? 具。

?志格式以下?個指標是必須得有的

  • 時間戳
  • ?志等級
  • ?志內容

以下幾個指標是可選的

  • 文件名行號
  • 進程,線程相關id信息等

?志有現成的解決?案,如:spdlog、glog、Boost.Log、Log4cxx等等,我們依舊采??定義?志的方式。

這?我們采?設計模式-策略模式來進??志的設計,

策略模式是一種行為型設計模式,它允許在運行時選擇算法或行為。該模式將算法族定義為一組可互換的策略,使得算法可以獨立于使用它的客戶端變化。

策略模式基于以下設計原則:

  • 封裝變化:將易變的算法部分單獨封裝

  • 面向接口編程:定義策略接口,而不是具體實現

  • 組合優于繼承:通過組合策略對象來獲得靈活性,而非通過繼承

策略模式包含三個主要角色:

  1. Context(上下文)

    • 維護對策略對象的引用

    • 可以定義一個接口讓策略訪問它的數據

  2. Strategy(策略接口)

    • 定義所有支持的算法的公共接口

    • Context使用這個接口調用具體策略定義的算法

  3. ConcreteStrategy(具體策略)

    • 實現策略接口的具體算法

例子:

#include <iostream>
#include <memory>// 策略接口
class SortingStrategy {
public:virtual void sort(int* data, int size) const = 0;virtual ~SortingStrategy() = default;
};// 具體策略A:快速排序
class QuickSort : public SortingStrategy {
public:void sort(int* data, int size) const override {std::cout << "Sorting using QuickSort\n";// 實際快速排序實現...}
};// 具體策略B:冒泡排序
class BubbleSort : public SortingStrategy {
public:void sort(int* data, int size) const override {std::cout << "Sorting using BubbleSort\n";// 實際冒泡排序實現...}
};// 上下文類
class Sorter {
private:std::unique_ptr<SortingStrategy> strategy;public:explicit Sorter(std::unique_ptr<SortingStrategy> strategy) : strategy(std::move(strategy)) {}void setStrategy(std::unique_ptr<SortingStrategy> newStrategy) {strategy = std::move(newStrategy);}void executeSort(int* data, int size) {strategy->sort(data, size);}
};int main() {int data[] = {5, 2, 7, 1, 9};Sorter sorter(std::make_unique<QuickSort>());sorter.executeSort(data, 5);  // 使用快速排序sorter.setStrategy(std::make_unique<BubbleSort>());sorter.executeSort(data, 5);  // 改為冒泡排序return 0;
}

我們想要的?志格式如下:

[可讀性很好的時間] [?志等級] [進程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

log.hpp

#pragma once
#include <iostream>
#include <string>
#include "Mutex.hpp"
#include <filesystem> //c++17
#include <fstream>    //c++文件流
#include <sstream>    //c++字符串流
#include <memory>
#include <time.h>//基于策略模式的日志
namespace LogModule
{using namespace LockModule;// 獲取時間的函數std::string CurrentTime(){time_t time_stamp = ::time(nullptr); // 獲取時間戳struct tm curr;//_r代表可以重入,支持多線程localtime_r(&time_stamp, &curr); // 將時間戳轉化成可讀性較強的時間信息char buffer[1024];// bugsnprintf(buffer, sizeof(buffer), "%4d-%02d-%02d %02d:%02d:%02d",curr.tm_year + 1900,curr.tm_mon + 1,curr.tm_mday,curr.tm_hour,curr.tm_min,curr.tm_sec);return buffer;}// 日志構成兩個階段: 一.構建日志信息  二.刷新落盤screen / file(向哪里刷新)// 二. 刷新落盤// 1. 日志文件的默認路徑和名稱const std::string dafaultlogpath = "./log/";const std::string dafaultlogname = "log.txt";// 2. 日志等級enum class LogLevel{DEBUG = 1,INFO, // 正常的WARNNING,ERROR,FATAL // 致命的};std::string Level2String(LogLevel level){switch (level){case LogLevel::DEBUG:return "DEBUG";case LogLevel::INFO:return "INFO";case LogLevel::WARNNING:return "WARNNING";case LogLevel::ERROR:return "ERROR";case LogLevel::FATAL:return "FATAL";default:return "NONE";}}// 3.刷新策略class LogStrategy // 基類{public:virtual ~LogStrategy() = default;   //虛析構函數(保證派生類對象能正確析構):確保通過基類指針刪除派生類對象時能正確調用派生類的析構函數virtual void SyncLog(const std::string &message) = 0;//純虛函數使得基類為抽象類 ,其派生類必須重構此函數才能構建對象};// 3.1控制臺策略class ConsoleLogStrategy : public LogStrategy{public:ConsoleLogStrategy(){}~ConsoleLogStrategy(){}void SyncLog(const std::string &message){// 屏幕也是臨界資源LockGuard lockguard(_mutex);std::cout << message << std::endl;}private:Mutex _mutex;};// 3.2文件級策略class FileLogStrategy : public LogStrategy{public:FileLogStrategy(const std::string &logpath = dafaultlogpath, const std::string &logname = dafaultlogname): _logpath(logpath),_logname(logname){LockGuard lockguard(_mutex);// 確認_logpath存在if (std::filesystem::exists(_logpath)){return;}try{std::filesystem::create_directories(_logpath);}catch (std::filesystem::filesystem_error &e){std::cerr << e.what() << "\n";}}~FileLogStrategy(){}void SyncLog(const std::string &message){LockGuard lockguard(_mutex);// c++文件操作std::string log = _logpath + _logname;// 創建一個ofstream文件輸出流對象,以追加模式打開日志文件std::ofstream out(log, std::ios::app); // 日志是追加寫入if (!out.is_open()){return;}out << message << "\n";out.close();}private:std::string _logpath;std::string _logname;Mutex _mutex; // 保證資源安全};// 一. 構建日志信息// 日志類 ,構建日志字符串(內部類實現) ,根據策略進行刷新class Logger{public:Logger(){// 默認使用控制臺刷新_strategy = std::make_shared<ConsoleLogStrategy>();}void EnableConsoleLog(){_strategy = std::make_shared<ConsoleLogStrategy>();}void EnableFileLog(){_strategy = std::make_shared<FileLogStrategy>();}~Logger(){}// 定義了內部類   一個logmessage就包含了一條完整的日志信息//  一條完整的日志信息: [2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [16] + 日志的可變部分(<< "hello world" << 3.14 << a << b;)class LogMessage{public:LogMessage(LogLevel level, const std::string &filename, int line, Logger &logger): _currtime(CurrentTime()), _level(level), _pid(getpid()), _src_name(filename), _line(line), _logger(logger){// 用stringstream進行流式拼接std::stringstream ssbuffer;ssbuffer << "[" << _currtime << "] "<< "[" << Level2String(_level) << "] " // 我們想要字符串式的日志等級<< "[" << _pid << "] "<< "[" << _src_name << "] "<< "[" << _line << "] - ";_loginfo = ssbuffer.str();}// LOG(DEBUG) << "hello " << 3.14 << a << b;想要實現需要重載<<template <typename T>LogMessage &operator<<(const T &info) // 返回使用引用 (要保證后面的信息都拼接到同一個LogMessage){std::stringstream ss;ss << info;_loginfo += ss.str();return *this; // 返回自己}~LogMessage(){// 析構時,執行Logger所對應的根據指定策略進行刷新一條方法if (_logger._strategy)//設置策略了就刷新{_logger._strategy->SyncLog(_loginfo);}}private:std::string _currtime; // 時間LogLevel _level;       // 日志等級pid_t _pid;            // 進程pidstd::string _src_name; // 原文件名稱int _line;             // 行號Logger &_logger;       // 負責根據不同的策略進行刷新std::string _loginfo;  // 一條完整的日志信息};// 仿函數重載() ,返回一個完整的日志信息// 故意沒有寫引用 ,就是要拷貝,返回臨時的LogMessage??? 臨時的LogMessage 自動析構時 自動刷新日志  LogMessage operator()(LogLevel level, const std::string &filename, int line){return LogMessage(level, filename, line, *this);}private:std::shared_ptr<LogStrategy> _strategy; // 日志的刷新方案// LogStrategy是純虛類 ,不能定義對象,能定義指針};// 使用Logger logger;#define LOG(level) logger(level, __FILE__, __LINE__) //__是預處理符    logger()運算符重載
#define ENABLE_CONSOLE_LOG() logger.EnableConsoleLog()
#define ENABLE_FILE_LOG() logger.EnableFileLog()
}

Main.cc

#include"log.hpp"using namespace LogModule;int main()
{//用C++版的流,實現可變參數//日志輸出格式//LOG(DEBUG) << "hello " << 3.14 << a << b;//會被替換成下面格式//logger(level ,__FILE__ ,__LINE__)<< "hello " << 3.14 << a << b;    //()執行完構建一個臨時的LogMessage,臨時的LogMessage會執行<<//LogMessage<< "hello " << 3.14 << a << b;        //LogMessage重載了<<ENABLE_FILE_LOG();LOG(LogLevel::INFO)<<"hello"<<666;return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/906010.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/906010.shtml
英文地址,請注明出處:http://en.pswp.cn/news/906010.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解鎖Ubuntu高效部署!自動安裝配置文件YAML全解析

我們之前介紹了兩種Ubuntu系統的安裝方式&#xff0c;分別對應桌面版&#xff08;準備搞OpenStack了&#xff0c;先裝一臺最新的Ubuntu 23.10&#xff09;和服務器版&#xff08;Ubuntu 22.04 LTS服務器版本安裝演示&#xff09;。但對于有些用戶&#xff0c;因為技術問題&…

關系代數和關系數據庫語言(SQL)

閱讀提示&#xff1a;本篇文章較長&#xff0c;建議從目錄上選取想看的內容。代碼上的話&#xff0c;我習慣用小寫&#xff0c;如果看不習慣建議跳過。有問題歡迎討論&#xff01;&#xff01;&#xff01; 一、基礎概念 1.1數據庫的概念 數據庫(Database)是按照數據結構來組…

EXO 可以將 Mac M4 和 Mac Air 連接起來,并通過 Ollama 運行 DeepSeek 模型

EXO 可以將 Mac M4 和 Mac Air 連接起來&#xff0c;并通過 Ollama 運行 DeepSeek 模型。以下是具體實現方法&#xff1a; 1. EXO 的分布式計算能力 EXO 是一個支持 分布式 AI 計算 的開源框架&#xff0c;能夠將多臺 Mac 設備&#xff08;如 M4 和 Mac Air&#xff09;組合成…

區塊鏈基本理解

文章目錄 前言一、什么是分布式賬本(DLT)二、什么是P2P網絡?二、共識算法三、密碼算法前言 區塊鏈是由一個一個數據塊組成的鏈條,按照時間順序將數據塊逐一鏈接,通過哈希指針鏈接,所有的數據塊共同維護一份分布式賬本(DLT),每個節點(可以理解為一個玩家,一臺計算機)都擁…

Node.js中的洋蔥模型

文章目錄 前言 前言 Node.js中的洋蔥模型是一種中間件執行機制&#xff0c;主要用于處理HTTP請求和響應的流程控制。該模型通過層層包裹的中間件結構&#xff0c;實現請求從外到內穿透、響應從內向外返回的順序執行。以下從核心概念、實現原理、框架差異及實際應用等方面解析&…

UI-TARS Desktop:用自然語言操控電腦,AI 重新定義人機交互

在人工智能技術飛速發展的今天,從文本生成到圖像識別,AI 的能力邊界不斷被打破。而字節跳動近期開源的 UI-TARS Desktop,則將這一技術推向了更復雜的交互場景——通過自然語言直接控制計算機界面,實現了圖形用戶界面(GUI)的智能化自動化。這款工具不僅降低了操作門檻,更…

一個可拖拉實現列表排序的WPF開源控件

從零學習構建一個完整的系統 推薦一個可通過拖拉&#xff0c;來實現列表元素的排序的WPF控件。 項目簡介 gong-wpf-dragdrop是一個開源的.NET項目&#xff0c;用于在WPF應用程序中實現拖放功能&#xff0c;可以讓開發人員快速、簡單的實現拖放的操作功能。 可以在同一控件內…

C語言中字符串函數的詳細講解

C語言提供了豐富的字符串處理函數&#xff0c;這些函數在<string.h>頭文件中聲明。以下是一些常用字符串函數的詳細講解&#xff1a; 字符串拷貝函數 strcpy 功能&#xff1a;將源字符串&#xff08;包括結尾的\0&#xff09;復制到目標字符串。原型&#xff1a;char *s…

可視化數據圖表怎么做?如何實現三維數據可視化?

目錄 一、三維數據可視化的要點 1. 明確數據可視化的目標 2. 篩選與整理數據 3. 選擇合適的圖表類型 4. 運用專業工具制作 5. 優化圖表的展示效果 二、數據可視化圖表怎么做&#xff1f; 1. 理解三維數據的特性 2. 數據處理與三維建模 3. 設置光照與材質效果 4. 添加…

在Linux服務器上部署Jupyter Notebook并實現ssh無密碼遠程訪問

Jupyter notebook版本7.4.2&#xff08;這個版本AI提示我Jupyter7&#xff08;底層是 jupyter_server 2.x&#xff09; 服務器開啟服務 安裝Jupyter notebook 7.4.2成功后&#xff0c;終端輸入 jupyter notebook --generate-config 這將在 ~/.jupyter/ 目錄下生成 jupyter_…

走出 Demo,走向現實:DeepSeek-VL 的多模態工程路線圖

目錄 一、引言&#xff1a;多模態模型的關鍵轉折點 &#xff08;一&#xff09;當前 LMM 的三個關鍵挑戰 1. 數據的真實性不足 2. 模型設計缺乏場景感知 3. 語言能力與視覺能力難以兼顧 &#xff08;二&#xff09;DeepSeek-VL 的根本出發點&#xff1a;以真實任務為錨點…

數據庫原理及其應用 第六次作業

題目 參考答案 題目1. 教材P148第1題 問題&#xff1a;什么是數據庫的安全性&#xff1f; 答案&#xff1a;數據庫的安全性是指保護數據庫以防止不合法的使用所造成的數據泄露、更改或破壞 。它通過用戶身份鑒別、存取控制&#xff08;包括自主存取控制和強制存取控制&#x…

2025系統架構師---選擇題知識點(押題)

1.《計算機信息系統安全保護等級劃分準則》(GB 17859-1999)由低到高定義了五個不同級別的計算機系統安全保護能力。 第一級:用戶自主保護級---通過隔離用戶與數據實現訪問控制,保護用戶信息安全; 第二級:系統審計保護級---實施更細粒度的訪問控制,通過審計和隔離資源確…

Qt操作SQLite數據庫教程

Qt 中操作 SQLite 數據庫的步驟如下&#xff1a; 1. 添加 SQLite 驅動并打開數據庫 #include <QSqlDatabase> #include <QSqlError> #include <QSqlQuery>// 創建數據庫連接 QSqlDatabase db QSqlDatabase::addDatabase("QSQLITE"); db.setData…

從紫光集團看基本財務分析

PE 46PE 代表投資人對他的期望是它的業績至少要增長50%才算及格。 但實際業績 一年不如一年. 所以&#xff0c;這個PE 應該是 業績倒退了&#xff0c;但是市值還沒有掉下去&#xff0c;導致運算的結果處在高PE階段。 那么隨著股價的下跌&#xff0c;這個數字會慢慢變小。 當然…

基于MNIST數據集的手寫數字識別(CNN)

目錄 一&#xff0c;模型訓練 1.1 數據集介紹 1.2 CNN模型層結構 1.3 定義CNN模型 1.4 神經網絡的前向傳播過程 1.5 數據預處理 1.6 加載數據 1.7 初始化 1.8 模型訓練過程 1.9 保存模型 二&#xff0c;模型測試 2.1 定義與訓練時相同的CNN模型架構 2.2 圖像的預處…

centos中postfix的作用

/usr/libexec/postfix/master 是 Postfix 郵件服務器的主進程&#xff0c;qmgr 和 pickup 是 Postfix 的子進程。這些進程本身是正常的&#xff0c;但如果你懷疑服務器被用于釣魚活動&#xff0c;需要進一步檢查 Postfix 的配置和日志&#xff0c;確保它沒有被濫用。 1. 檢查 P…

藍牙耳機什么牌子好?倍思值得沖不?

最近總被問“藍牙耳機什么牌子好”&#xff0c;作為踩過無數坑的資深耳機黨&#xff0c;必須安利剛入手的倍思M2s Pro主動降噪藍牙耳機&#xff01;降噪、音質、顏值全都在線&#xff0c;性價比直接拉滿。 -52dB降噪&#xff0c;通勤摸魚神器 第一次開降噪就被驚到&#xff01…

游戲引擎學習第285天:“Traversables 的事務性占用”

回顧并為當天的工作做準備 我們有一個關于玩家移動的概念&#xff0c;玩家可以在點之間移動&#xff0c;而且當這些點移動時&#xff0c;玩家會隨之移動。現在這個部分基本上已經在工作了。我們本來想實現的一個功能是&#xff1a;當玩家移動到某個點時&#xff0c;這個點能“…

java中的包機制

包機制 為了更好地組織類&#xff0c;java提供了包機制&#xff0c;用于區分類名的命名空間 包語句的語法格式為 package pkg1[. pkg2[. pkg3...]]一般利用公司域名倒置作為包名 &#xff1a; 公司域名&#xff1a;www.baidu.com 包名&#xff1a;com.baidu.www 為了能夠…