亚洲国产第一_开心网五月色综合亚洲_日本一级特黄特色大片免费观看_久久久久久久久久免观看

Hello! 歡迎來到小浪云!


【Linux】日志設(shè)計模式與實現(xiàn)


avatar
小浪云 2025-04-17 28

1. 什么是設(shè)計模式

??it行業(yè)這么火, 涌入的人很多. 俗話說林子大了啥鳥都有. 大佬和菜雞們兩極分化的越來越嚴重. 為了讓菜雞們不太拖大佬的后腿, 于是大佬們針對?些經(jīng)典的常見的場景, 給定了?些對應(yīng)的解決?案, 這個就是設(shè)計模式。 ??在it行業(yè)中,設(shè)計模式(design patterns) 是一套被廣泛認可的、用于解決軟件設(shè)計中常見問題的最佳實踐。它們提供了一種標準化的方法來處理特定的設(shè)計問題,并且可以幫助開發(fā)人員編寫更清晰、更具可維護性的代碼。

2. 日志認識

??計算機中的日志是記錄系統(tǒng)和軟件運行中發(fā)生事件的文件,主要作用是監(jiān)控運行狀態(tài)、記錄異常信息,幫助快速定位問題并?持程序員進?問題修復(fù)。它是系統(tǒng)維護、故障排查和安全管理的重要工具。 日志格式以下幾個指標是必須得有的:

時間戳日志等級日志內(nèi)容

以下幾個指標是可選的:

文件名行號進程,線程相關(guān)id信息等 日志有現(xiàn)成的解決方案,如:spdlog、glog、Boost.Log、Log4cxx等等,我們依舊采用自定義日志的方式。這里我們采用設(shè)計模式-策略模式來進行日志的設(shè)計,我們想要的日志格式如下:代碼語言:JavaScript代碼運行次數(shù):0運行復(fù)制

[可讀性很好的時間] [?志等級] [進程pid] [打印對應(yīng)?志的?件名][?號] - 消息內(nèi)容,?持可變參數(shù)[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

3. 日志實現(xiàn)首先我們需要設(shè)置日志等級:代碼語言:javascript代碼運行次數(shù):0運行復(fù)制

// ?志等級    enum class LogLevel    {        DEBUG,        INFO,        WARNING,        ERROR,        FATAL    };    // ?志轉(zhuǎn)換成為字符串    std::string LogLevelToString(LogLevel level)    {        switch (level)        {        case LogLevel::DEBUG:            return "DEBUG";        case LogLevel::INFO:            return "INFO";        case LogLevel::WARNING:            return "WARNING";        case LogLevel::ERROR:            return "ERROR";        case LogLevel::FATAL:            return "FATAL";        default:            return "UNKNOWN";        }    }

設(shè)置日志時間代碼語言:javascript代碼運行次數(shù):0運行復(fù)制

    // 根據(jù)時間戳,獲取可讀性較強的時間信息    std::string GetCurrTime()    {        time_t tm = time(nullptr);        struct tm curr;        localtime_r(&tm, &curr);        char timebuffer[64];        snprintf(timebuffer, sizeof(timebuffer), "%4d-%02d-%02d %02d:%02d:%02d ",                 curr.tm_year + 1900,//這是因為這里的年份比實際年份少1900                 curr.tm_mon+1,//這是因為月份是在0~11                 curr.tm_mday,                 curr.tm_hour,                 curr.tm_min,                 curr.tm_sec);        return timebuffer;    }

日志策略模式:

??有了準備工作后,我們在開始設(shè)計日志類之前還需要確定日志的策略模式——也就是日志是往控制臺上輸出還是文件中輸出。

代碼語言:javascript代碼運行次數(shù):0運行復(fù)制

// 策略模式,策略接?    class LogStrategy    {    public:        virtual ~LogStrategy() = default;                     // 策略的析構(gòu)函數(shù)        virtual void SyncLog(const std::string &message) = 0; // 不同模式核?是刷新?式的不同    };

控制臺日志策略:代碼語言:javascript代碼運行次數(shù):0運行復(fù)制

// 控制臺?志策略,就是?志只向顯?器打印,?便我們debug    class ConsoleLogStrategy : public LogStrategy    {    public:        void SyncLog(const std::string &amp;message) override        {            LockGuard LockGuard(_mutex);            std::cerr 文件日志策略:代碼語言:javascript<i class="icon-code"></i>代碼運行次數(shù):<!-- -->0<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewbox="0 0 16 16" fill="none"><path d="M6.66666 10.9999L10.6667 7.99992L6.66666 4.99992V10.9999ZM7.99999 1.33325C4.31999 1.33325 1.33333 4.31992 1.33333 7.99992C1.33333 11.6799 4.31999 14.6666 7.99999 14.6666C11.68 14.6666 14.6667 11.6799 14.6667 7.99992C14.6667 4.31992 11.68 1.33325 7.99999 1.33325ZM7.99999 13.3333C5.05999 13.3333 2.66666 10.9399 2.66666 7.99992C2.66666 5.05992 5.05999 2.66659 7.99999 2.66659C10.94 2.66659 13.3333 5.05992 13.3333 7.99992C13.3333 10.9399 10.94 13.3333 7.99999 13.3333Z" fill="currentcolor"></path></svg>運行<svg width="16" height="16" viewbox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 15.5V3.5H14.5V15.5H4.5ZM12.5 5.5H6.5V13.5H12.5V5.5ZM9.5 2.5H3.5V12.5H1.5V0.5H11.5V2.5H9.5Z" fill="currentcolor"></path></svg>復(fù)制<pre class="prism-token token line-numbers javascript">    class FileLogStrategy : public LogStrategy    {    public:        // 構(gòu)造函數(shù),建?出來指定的?錄結(jié)構(gòu)和?件結(jié)構(gòu)        FileLogStrategy(const std::string logpath = defaultpath, std::string logfilename = defaultname)            : _logpath(logpath), _logfilename(logfilename)        {            LockGuard lockguard(_mutex);            if (std::filesystem::exists(_logpath))                return;            try            {                std::filesystem::create_directories(_logpath);            }            catch (const std::filesystem::filesystem_error &amp;e)            {                std::cerr 具體日志類:<p>我們先確定日志策略模式,默認是控制臺輸出;然后定義一個內(nèi)部類用來確定日志輸出的信息:</p>代碼語言:javascript<i class="icon-code"></i>代碼運行次數(shù):<!-- -->0<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewbox="0 0 16 16" fill="none"><path d="M6.66666 10.9999L10.6667 7.99992L6.66666 4.99992V10.9999ZM7.99999 1.33325C4.31999 1.33325 1.33333 4.31992 1.33333 7.99992C1.33333 11.6799 4.31999 14.6666 7.99999 14.6666C11.68 14.6666 14.6667 11.6799 14.6667 7.99992C14.6667 4.31992 11.68 1.33325 7.99999 1.33325ZM7.99999 13.3333C5.05999 13.3333 2.66666 10.9399 2.66666 7.99992C2.66666 5.05992 5.05999 2.66659 7.99999 2.66659C10.94 2.66659 13.3333 5.05992 13.3333 7.99992C13.3333 10.9399 10.94 13.3333 7.99999 13.3333Z" fill="currentcolor"></path></svg>運行<svg width="16" height="16" viewbox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 15.5V3.5H14.5V15.5H4.5ZM12.5 5.5H6.5V13.5H12.5V5.5ZM9.5 2.5H3.5V12.5H1.5V0.5H11.5V2.5H9.5Z" fill="currentcolor"></path></svg>復(fù)制<pre class="prism-token token line-numbers javascript"> // 具體的?志類    class Logger    {    public:        Logger()        {            // 默認使?顯?器策略,如果???次指明了策略,會釋放在申請,測試的時候注意析構(gòu)次數(shù)            UseConsoleStrategy();        }        ~Logger()        {        }        void UseConsoleStrategy()        {            _strategy = std::make_unique<consolelogstrategy>();        }        void UseFileStrategy()        {            _strategy = std::make_unique<filelogstrategy>();        }        class LogMessage        {        public:            LogMessage(LogLevel type, std::string filename, int line, Logger &amp;logger)                : _curr_time(GetCurrTime()),                  _pid(getpid()),                  _filename(filename),                  _line(line),                  _logger(logger)            {                // stringstream不允許拷?,所以這?就當做格式化功能使?                std::stringstream ssbuffer;                ssbuffer             LogMessage &amp;operatorSyncLog(_loginfo);                }            }        private:            LogLevel _type;         // ?志等級            std::string _curr_time; // ?志時間            pid_t _pid;             // 寫??志的進程ID            std::string _filename;  // 對應(yīng)的?件名            int _line;              // 對應(yīng)的?件?號            Logger &amp;_logger;        // 引?外部logger類, ?便使?策略進?刷新            std::string _loginfo;   // ?條合并完成的,完整的?志信息        };        LogMessage operator()(LogLevel type, std::string filename, int line)        {            return LogMessage(type, filename, line, *this);        }    private:        std::unique_ptr<logstrategy> _strategy;    };</logstrategy></filelogstrategy></consolelogstrategy>

最后將上述內(nèi)容放在一個命名空間LogModule內(nèi)部,并定義一個日志類對象:代碼語言:javascript代碼運行次數(shù):0運行復(fù)制

#include #include #include #include #include #include #include  // C++17, 需要?版本編譯器和-std=c++17#include #include "Mutex.hpp"namespace LogModule{    using namespace MutexModule;    // 默認路徑和?志名稱    const std::string defaultpath = "./log/";    const std::string defaultname = "log.txt";    // ?志等級    enum class LogLevel    {        DEBUG,        INFO,        WARNING,        ERROR,        FATAL    };    // ?志轉(zhuǎn)換成為字符串    std::string LogLevelToString(LogLevel level)    {        switch (level)        {        case LogLevel::DEBUG:            return "DEBUG";        case LogLevel::INFO:            return "INFO";        case LogLevel::WARNING:            return "WARNING";        case LogLevel::ERROR:            return "ERROR";        case LogLevel::FATAL:            return "FATAL";        default:            return "UNKNOWN";        }    }    // 根據(jù)時間戳,獲取可讀性較強的時間信息    std::string GetCurrTime()    {        time_t tm = time(nullptr);        struct tm curr;        localtime_r(&tm, &curr);        char timebuffer[64];        snprintf(timebuffer, sizeof(timebuffer), "%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 timebuffer;    }    // 策略模式,策略接?    class LogStrategy    {    public:        virtual ~LogStrategy() = default;                     // 策略的構(gòu)造函數(shù)        virtual void SyncLog(const std::string &message) = 0; // 不同模式核?是刷新?式的不同    };    // 控制臺?志策略,就是?志只向顯?器打印,?便我們debug    class ConsoleLogStrategy : public LogStrategy    {    public:        void SyncLog(const std::string &message) override        {            LockGuard LockGuard(_mutex);            std::cerr ();        }        void UseFileStrategy()        {            _strategy = std::make_unique();        }        class LogMessage        {        public:            LogMessage(LogLevel type, std::string filename, int line, Logger &logger)                : _curr_time(GetCurrTime()),                  _pid(getpid()),                  _filename(filename),                  _line(line),                  _logger(logger)            {                // stringstream不允許拷?,所以這?就當做格式化功能使?                std::stringstream ssbuffer;                ssbuffer             LogMessage &operatorSyncLog(_loginfo);                }            }        private:            LogLevel _type;         // ?志等級            std::string _curr_time; // ?志時間            pid_t _pid;             // 寫??志的進程ID            std::string _filename;  // 對應(yīng)的?件名            int _line;              // 對應(yīng)的?件?號            Logger &_logger;        // 引?外部logger類, ?便使?策略進?刷新            std::string _loginfo;   // ?條合并完成的,完整的?志信息        };        LogMessage operator()(LogLevel type, std::string filename, int line)        {            return LogMessage(type, filename, line, *this);        }    private:        std::unique_ptr _strategy;    };    //定義日志類對象    Logger logger;    // 使?宏,可以進?代碼插?,?便隨時獲取?件名和?號    #define LOG(type) logger(type, __FILE__, __LINE__)    // 提供選擇使?何種?志策略的?法    #define ENABLE_CONSOLE_LOG_STRATEGY() logger.UseConsoleStrategy()    #define ENABLE_FILE_LOG_STRATEGY() logger.UseFileStrategy()}

測試代碼:代碼語言:javascript代碼運行次數(shù):0運行復(fù)制

#include <iostream>#include "Log.hpp"using namespace LogModule;void fun(){    int a = 10;    LOG(LogLevel::FATAL) <p>結(jié)果如下:</p> <figure class=""><img src="https://img.php.cn/upload/article/001/503/042/174487142432849.jpg" alt="【Linux】日志設(shè)計模式與實現(xiàn)"></figure>4. 結(jié)語<p>??日志可以幫助我們快速準確的了解程序運行的狀況,出現(xiàn)的錯誤以及相關(guān)內(nèi)容;同時日志的設(shè)計模式如解耦也值得我們學(xué)習(xí)。</p></iostream>

相關(guān)閱讀