九色91_成人精品一区二区三区中文字幕_国产精品久久久久一区二区三区_欧美精品久久_国产精品99久久久久久久vr_www.国产视频

Hello! 歡迎來到小浪云!


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


avatar
小浪云 2025-04-17 43

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

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

2. 日志認(rèn)識

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

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

以下幾個指標(biāo)是可選的:

文件名行號進程,線程相關(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;    }

日志策略模式:

??有了準(zhǔn)備工作后,我們在開始設(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>我們先確定日志策略模式,默認(rèn)是控制臺輸出;然后定義一個內(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()        {            // 默認(rèn)使?顯?器策略,如果???次指明了策略,會釋放在申請,測試的時候注意析構(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不允許拷?,所以這?就當(dāng)做格式化功能使?                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;    // 默認(rèn)路徑和?志名稱    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不允許拷?,所以這?就當(dāng)做格式化功能使?                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>??日志可以幫助我們快速準(zhǔn)確的了解程序運行的狀況,出現(xiàn)的錯誤以及相關(guān)內(nèi)容;同時日志的設(shè)計模式如解耦也值得我們學(xué)習(xí)。</p></iostream>

相關(guān)閱讀

主站蜘蛛池模板: 亚洲综合大片69999 | 日本精品视频 | 中文在线亚洲 | 国产一级免费视频 | 不卡在线视频 | 国产成人精品免费 | 国产精品一区二区av | 欧美精品乱码久久久久久按摩 | 亚洲午夜电影 | 亚洲精品久久久久久久久久久久久 | 精品国产一区二区三区日日嗨 | 国产一区亚洲二区三区 | a国产一区二区免费入口 | 精品国产乱码一区二区三 | 精品国产乱码久久久久久a丨 | 亚洲国产成人精品女人久久久野战 | 欧美炮房| 免费视频一区 | 亚洲午夜精品一区二区三区他趣 | 日本精品一区二区在线观看 | 国产精品一区二区视频 | 欧美激情一区二区三区 | 日韩av免费在线观看 | 日日夜夜免费精品视频 | 国产精品欧美大片 | 一区视频 | 国产精品三级久久久久久电影 | 久久久999免费视频 999久久久久久久久6666 | 人人鲁人人莫人人爱精品 | 国产精品不卡一区 | 亚洲天堂一区二区 | 四色成人av永久网址 | 亚洲国产精久久久久久久 | 色天堂影院 | 亚洲一区二区三区免费观看 | 国产精品久久久久久久久久久久久 | 一区二区免费 | 免费三级网 | 国产精品大片在线观看 | av超碰 | 在线亚洲一区二区 |