C++還在printf/cout進行Debug?學(xué)習(xí)一下如何自己寫日志庫吧(上篇)

      網(wǎng)友投稿 1380 2025-03-31

      文章目錄

      一. 前言

      二. 基本功能

      三. 代碼實現(xiàn)

      1. fdoglogger.h

      2. fdoglogger.cpp

      四. 測試用例

      1. fdoglogger_test.cpp

      哈嘍,自從實習(xí)以來很久沒有更文了,一是沒有時間,二是實習(xí)了之后突然發(fā)現(xiàn)自己能寫的東西也沒有多少了。趕上1024有征文活動,就寫一篇吧,在實習(xí)的這段時間,我更加認識到日志的重要性,客戶端值沒傳過來?看日志,服務(wù)崩潰了?看日志,沒錯,日志是出現(xiàn)異常第一個想到的東西,它記錄了程序運行過程中所調(diào)用的函數(shù),所接受到的值,所執(zhí)行的行為等等。大家也都看到這篇的標題了,我這個人有一個缺點,就是不太喜歡用別人的東西,如果有能力,我希望自己造,所以今天我們自己來動手擼一個日志庫,文章重點講實現(xiàn)過程,如果需要源碼,可以前往github獲取FdogLog,一個輕量級C++日志庫,用于日志服務(wù)。

      跪求三連!

      我們先來捋一捋這個日志庫應(yīng)該實現(xiàn)那些功能。

      日志最最最基本的功能是什么,當(dāng)然是打印或記錄日志。

      信息應(yīng)該包括哪些信息,時間?運行用戶?所在文件?想要顯示的信息?(自定義顯示信息下篇實現(xiàn))

      信息雖然顯示豐富,但是要盡可能讓代碼自己獲取其他信息,調(diào)用者只需要設(shè)置最主要的信息。

      信息有重要等級之分,所以我們需要對信息做必要分類,提高效率。

      如何實現(xiàn)全局盡可能簡潔的調(diào)用。

      如果日志庫是運行在多線程環(huán)境,如何保證線程安全。(下篇實現(xiàn))

      這些就是一個日志庫所具備的最基本的功能,接下來繼續(xù)思考,還需要什么。

      怎么控制日志的行為。

      如果保存在文件,如何定義文件名。

      隨著日志增加,文件會越來越大,如何解決。(下篇實現(xiàn))

      簡單規(guī)劃完一個不那么完美的日志庫所具備的能力,現(xiàn)在我們來對這幾條做更詳細的規(guī)劃。

      日志最最最基本的功能是什么,當(dāng)然是打印或記錄日志。

      信息應(yīng)該包括哪些信息,時間?運行用戶?所在文件?想要顯示的信息?

      當(dāng)我在調(diào)用一個名為function的函數(shù)時。

      function();

      1

      你希望它輸出怎么樣的信息。

      我被調(diào)用

      [2021-10-20 23:27:23] 我被調(diào)用

      [2021-10-20 23:27:23] INFO 我被調(diào)用

      [2021-10-20 23:27:23] INFO root 我被調(diào)用

      [2021-10-20 23:27:23] INFO root 17938 我被調(diào)用

      [2021-10-20 23:27:23] INFO root 17938 [/media/rcl/FdogIM/service.h function:8] 我被調(diào)用

      我想大部分人都會選擇最后一種輸出信息吧(雖然在這之前,我們都大量使用cout輸出第一種),所以我們的日志應(yīng)該包括時間,日志等級,運行用戶,進程ID,調(diào)用函數(shù)所在文件,以及調(diào)用時所在行數(shù)。當(dāng)然總會有人不想全部輸出,這將在后面給出方案。

      信息雖然顯示豐富,但是要盡可能讓代碼自己獲取其他信息,調(diào)用者只需要設(shè)置最主要的信息。

      信息有重要等級之分,所以我們需要對信息做必要分類,提高效率。

      如何實現(xiàn)全局盡可能簡潔的調(diào)用.

      信息有重要等級之分,要可以對信息做區(qū)分,按照常見的等級之分,有:

      ERROR:?此信息輸出后,主體系統(tǒng)核心模塊不能正常工作,需要修復(fù)才能正常工作。

      WARN:?? 此信息輸出后,系統(tǒng)一般模塊存在問題,不影響系統(tǒng)運行。

      INFO:?????此信息輸出后,主要是記錄系統(tǒng)運行狀態(tài)等關(guān)聯(lián)信息。

      DEBUG:?最細粒度的輸出,除去上面各種情況后,你希望輸出的相關(guān)信息,都可以在這里輸出。

      TRACE:??最細粒度的輸出,除去上面各種情況后,你希望輸出的相關(guān)信息,都可以在這里輸出。

      有了等級之分,如何實現(xiàn)全局盡可能簡潔的調(diào)用,通俗的說就是去掉一切不必要的調(diào)用,只留下最主要的調(diào)用。

      例如:

      #include #include"fdoglogger.h" //添加日志庫頭文件 using namespace fdog; //日志庫的命名空間 int main(){ FdogError("錯誤"); FdogWarn("警告"); FdogInfo("信息"); FdogDebug("調(diào)試"); FdogTrace("追蹤"); return 0; }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      你不必初始化什么信息,調(diào)用什么多余的初始化函數(shù),只需要用這五個類似函數(shù)的東西來輸出即可,同樣,如果是另一個源文件,依舊是這樣的調(diào)用方式(這里可以使用單一模式來實現(xiàn),其意圖是保證一個類僅有一個實列,并提供一個訪問它的全局訪問點,該實例被所有程序模塊共享。就比如日志的輸出。)。

      如果日志庫是運行在多線程環(huán)境,如何保證線程安全。

      到目前,一個基本的日志庫的調(diào)用基本成形,如果在單線程,它可以很好的工作,但是到了多線程環(huán)境下,就不能保證了,第一點就是單例模式的創(chuàng)建,當(dāng)兩個線程同時去初始化時,無法保證單一實例被成功創(chuàng)建,第二,日志既然是輸出到文件,不同線程寫入文件時,如何保證寫入數(shù)據(jù)不會錯亂。既然寫的是C++的日志輸出,必然用到了cout ,cout 不是原子性的操作,所以在多線程下是不安全的,這些都是我們需要考慮到的。

      怎么控制日志的行為。

      這里使用配置文件進行日志的行為規(guī)定,包括打印什么日志,輸入到文件,還是終端,輸出的等級,以及日志開關(guān),等等,配置文件將在程序啟動時被讀取。(提醒各位千萬不要寫死代碼,后患無窮!!!)

      如果保存在文件,如何定義文件名。

      隨著日志增加,文件會越來越大,如何解決。

      日志的文件名由配置文件指定,但是創(chuàng)建時會在后面加上創(chuàng)建日期后綴,并且可以在配置文件中配置每隔多少天創(chuàng)建一個新的日志文件,如果配置中心有設(shè)置日志文件大小,則會優(yōu)先大小判斷,超過便創(chuàng)建一個新文件。

      #ifndef FDOGLOGGER_H #define FDOGLOGGER_H #include #include #include #include #ifndef linux #include #include #include #include #include #endif #ifndef WIN32 //TODO #endif using namespace std; namespace fdog { #define RED "\e[1;31m" #define BLUE "\e[1;34m" #define GREEN "\e[1;32m" #define WHITE "\e[1;37m" #define DEFA "\e[0m" enum class coutType: int {Error, Warn, Info, Debug, Trace}; enum class fileType: int {Error, Warn, Info, Debug, Trace}; enum class terminalType: int {Error, Warn, Info, Debug, Trace}; struct Logger { string logSwitch; //日志開關(guān) string logFileSwitch; //是否寫入文件 string logTerminalSwitch; //是否打印到終端 string logName; //日志文件名字 string logFilePath; //日志文件保存路徑 string logMixSize; //日志文件最大大小 string logBehavior; //日志文件達到最大大小行為 string logOverlay; //日志文件覆蓋時間 string logOutputLevelFile; //日志輸出等級(file) string logOutputLevelTerminal;//日志輸出等級 }; class FdogLogger { public: void initLogConfig(); void releaseConfig(); static FdogLogger* getInstance(); string getCoutType(coutType coutType); bool getFileType(fileType fileCoutBool); bool getTerminalType(terminalType terminalCoutTyle); string getLogCoutTime(); string getLogNameTime(); string getFilePash(); string getLogCoutProcessId(); string getLogCoutThreadId(); string getLogCoutUserName(); bool createFile(string filePash); bool logFileWrite(string messages); bool bindFileCoutMap(string value1, fileType value2); bool bindTerminalCoutMap(string value1, terminalType value2); private: char szbuf[128]; Logger logger; static FdogLogger * singleObject; static mutex * mutex_new; map coutTypeMap; map fileCoutMap; map terminalCoutMap; private: FdogLogger(); ~FdogLogger(); }; #define Error1 __FDOGNAME__(Error) #define Warn1 __FDOGNAME__(Warn) #define Info1 __FDOGNAME__(Info) #define Debug1 __FDOGNAME__(Debug) #define Trace1 __FDOGNAME__(Trace) #define SQUARE_BRACKETS_LEFT " [" #define SQUARE_BRACKETS_RIGHT "] " #define SPACE " " #define LINE_FEED "\n" #define COLON ":" #define SLASH "/" #define __FDOGTIME__ FdogLogger::getInstance()->getLogCoutTime() //時間宏 #define __FDOGPID__ FdogLogger::getInstance()->getLogCoutProcessId() //進程宏 #define __FDOGTID__ FdogLogger::getInstance()->getLogCoutThreadId() //線程宏 #define __FDOGFILE__ __FILE__ //文件名宏 #define __FDOGPASH__ FdogLogger::getInstance()->getFilePash() + __FDOGFILE__ //文件路徑 #define __FDOGFUNC__ __func__ //函數(shù)名宏 #define __FDOGLINE__ __LINE__ //行數(shù)宏 #define __USERNAME__ FdogLogger::getInstance()->getLogCoutUserName() //獲取調(diào)用用戶名字 #define __FDOGNAME__(name) #name //名字宏 #define COMBINATION_INFO_FILE(coutTypeInfo, message) \ do{\ string messagesAll = __FDOGTIME__ + coutTypeInfo + __USERNAME__ + __FDOGTID__ + SQUARE_BRACKETS_LEFT + \ __FDOGPASH__ + SPACE +__FDOGFUNC__ + COLON + to_string(__FDOGLINE__) + SQUARE_BRACKETS_RIGHT + message + LINE_FEED;\ FdogLogger::getInstance()->logFileWrite(messagesAll); \ }while(0); #define COMBINATION_INFO_TERMINAL(coutTypeInfo, message) \ do{\ string messagesAll = __FDOGTIME__ + WHITE + coutTypeInfo + DEFA + __USERNAME__ + __FDOGTID__ + SQUARE_BRACKETS_LEFT + \ __FDOGPASH__ + SPACE +__FDOGFUNC__ + COLON + to_string(__FDOGLINE__) + SQUARE_BRACKETS_RIGHT + message + LINE_FEED;\ cout << messagesAll;\ }while(0); #define LoggerCout(coutTyle, coutTypeInfo, fileCoutBool, terminalCoutBool, message) \ do {\ string coutType = FdogLogger::getInstance()->getCoutType(coutTyle);\ if (FdogLogger::getInstance()->getFileType(fileCoutBool)) {\ COMBINATION_INFO_FILE(coutTypeInfo, message)\ }\ if (FdogLogger::getInstance()->getTerminalType(terminalCoutBool)) {\ COMBINATION_INFO_TERMINAL(coutTypeInfo, message)\ }\ }while(0); #define FdogError(message) \ do{\ LoggerCout(fdog::coutType::Error, Error1, fdog::fileType::Error, fdog::terminalType::Error, message)\ }while(0); #define FdogWarn(message) \ do{\ LoggerCout(fdog::coutType::Warn, Warn1, fdog::fileType::Warn, fdog::terminalType::Warn, message)\ }while(0); #define FdogInfo(message) \ do{\ LoggerCout(fdog::coutType::Info, Info1, fdog::fileType::Info, fdog::terminalType::Info, message)\ }while(0); #define FdogDebug(message) \ do{\ LoggerCout(fdog::coutType::Debug, Debug1, fdog::fileType::Debug, fdog::terminalType::Debug, message)\ }while(0); #define FdogTrace(message) \ do{\ LoggerCout(fdog::coutType::Trace, Trace1, fdog::fileType::Trace, fdog::terminalType::Trace, message)\ }while(0); } #endif

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      C++還在用printf/cout進行Debug?學(xué)習(xí)一下如何自己寫日志庫吧(上篇)

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      77

      78

      79

      80

      81

      82

      83

      84

      85

      86

      87

      88

      89

      90

      91

      92

      93

      94

      95

      96

      97

      98

      99

      100

      101

      102

      103

      104

      105

      106

      107

      108

      109

      110

      111

      112

      113

      114

      115

      116

      117

      118

      119

      120

      121

      122

      123

      124

      125

      126

      127

      128

      129

      130

      131

      132

      133

      134

      135

      136

      137

      138

      139

      140

      141

      142

      143

      144

      145

      146

      147

      148

      149

      150

      151

      152

      153

      154

      155

      156

      157

      158

      159

      160

      161

      162

      163

      164

      165

      166

      167

      168

      169

      170

      #include"fdoglogger.h" using namespace fdog; FdogLogger * FdogLogger::singleObject = nullptr; mutex * FdogLogger::mutex_new = new(mutex); FdogLogger::FdogLogger(){ initLogConfig(); } FdogLogger::~FdogLogger(){ } FdogLogger* FdogLogger::getInstance(){ mutex_new->lock(); if (singleObject == nullptr) { singleObject = new FdogLogger(); } mutex_new->unlock(); return singleObject; } void FdogLogger::initLogConfig(){ map flogConfInfo; flogConfInfo["logSwitch"] = &this->logger.logSwitch; flogConfInfo["logFileSwitch"] = &this->logger.logFileSwitch; flogConfInfo["logTerminalSwitch"] = &this->logger.logTerminalSwitch; flogConfInfo["logName"] = &this->logger.logName; flogConfInfo["logFilePath"] = &this->logger.logFilePath; flogConfInfo["logMixSize"] = &this->logger.logMixSize; flogConfInfo["logBehavior"] = &this->logger.logBehavior; flogConfInfo["logOverlay"] = &this->logger.logOverlay; flogConfInfo["logOutputLevelFile"] = &this->logger.logOutputLevelFile; flogConfInfo["logOutputLevelTerminal"] = &this->logger.logOutputLevelTerminal; string str; ifstream file; char str_c[100]={0}; file.open("fdoglogconf.conf"); if(!file.is_open()){ cout<<"文件打開失敗\n"; } while(getline(file, str)){ if(!str.length()) { continue; } string str_copy = str; //cout<<"獲取數(shù)據(jù):"<second = str_c; } else { } } } logger.logName = logger.logName + getLogNameTime() + ".log"; bindFileCoutMap("5", fileType::Error); bindFileCoutMap("4", fileType::Warn); bindFileCoutMap("3", fileType::Info); bindFileCoutMap("2", fileType::Debug); bindFileCoutMap("1", fileType::Trace); bindTerminalCoutMap("5", terminalType::Error); bindTerminalCoutMap("4", terminalType::Warn); bindTerminalCoutMap("3", terminalType::Info); bindTerminalCoutMap("2", terminalType::Debug); bindTerminalCoutMap("1", terminalType::Trace); if(logger.logFileSwitch == "on"){ if(!createFile(logger.logFilePath)){ std::cout<<"Log work path creation failed\n"; } } cout << "|========FdogLogger v2.0==========================|" <coutTypeMap[coutType]; } bool FdogLogger::getFileType(fileType fileCoutBool){ return singleObject->fileCoutMap[fileCoutBool]; } bool FdogLogger::getTerminalType(terminalType terminalCoutTyle){ return singleObject->terminalCoutMap[terminalCoutTyle]; } string FdogLogger::getLogCoutTime(){ time_t timep; time (&timep); char tmp[64]; strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S",localtime(&timep)); string tmp_str = tmp; return SQUARE_BRACKETS_LEFT + tmp_str + SQUARE_BRACKETS_RIGHT; } string FdogLogger::getLogNameTime(){ time_t timep; time (&timep); char tmp[64]; strftime(tmp, sizeof(tmp), "%Y-%m-%d-%H:%M:%S",localtime(&timep)); return tmp; } string FdogLogger::getFilePash(){ getcwd(szbuf, sizeof(szbuf)-1); string szbuf_str = szbuf; return szbuf_str + SLASH; } string FdogLogger::getLogCoutProcessId(){ #ifndef linux return to_string(getpid()); #endif #ifndef WIN32 // unsigned long GetPid(){ // return GetCurrentProcessId(); // } #endif } string FdogLogger::getLogCoutThreadId(){ #ifndef linux return to_string(syscall(__NR_gettid)); #endif #ifndef WIN32 // unsigned long GetTid(){ // return GetCurrentThreadId(); // } #endif } string FdogLogger::getLogCoutUserName(){ struct passwd *my_info; my_info = getpwuid(getuid()); string name = my_info->pw_name; return SPACE + name + SPACE; } bool FdogLogger::createFile(string filePash){ int len = filePash.length(); if(!len){ filePash = "log"; if (0 != access(filePash.c_str(), 0)){ if(-1 == mkdir(filePash.c_str(),0)){ std::cout<<"沒路徑"; return 0; } } } std::string filePash_cy(len,'\0'); for(int i =0;i

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      77

      78

      79

      80

      81

      82

      83

      84

      85

      86

      87

      88

      89

      90

      91

      92

      93

      94

      95

      96

      97

      98

      99

      100

      101

      102

      103

      104

      105

      106

      107

      108

      109

      110

      111

      112

      113

      114

      115

      116

      117

      118

      119

      120

      121

      122

      123

      124

      125

      126

      127

      128

      129

      130

      131

      132

      133

      134

      135

      136

      137

      138

      139

      140

      141

      142

      143

      144

      145

      146

      147

      148

      149

      150

      151

      152

      153

      154

      155

      156

      157

      158

      159

      160

      161

      162

      163

      164

      165

      166

      167

      168

      169

      170

      171

      172

      173

      174

      175

      176

      177

      178

      179

      180

      181

      182

      183

      184

      185

      186

      187

      188

      189

      190

      191

      192

      193

      194

      195

      196

      197

      198

      199

      200

      201

      202

      203

      204

      205

      206

      207

      208

      209

      210

      211

      212

      213

      214

      215

      216

      217

      218

      219

      220

      221

      #include #include"fdoglogger.h" //添加日志庫頭文件 using namespace fdog; //日志庫的命名空間 int main(){ FdogError("錯誤"); FdogWarn("警告"); FdogInfo("信息"); FdogDebug("調(diào)試"); FdogTrace("追蹤"); return 0; }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      暫時考慮到的就是這些,如有缺陷,歡迎評論區(qū)補充。(比如文件寫入打開就關(guān)閉,很浪費資源,如何優(yōu)化,下篇見)。

      源碼已上傳github,還原star! FdogLog,一個輕量級C++日志庫,用于日志服務(wù)。

      C++ 任務(wù)調(diào)度

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:向WPS表中的數(shù)據(jù)添加三維效果邊框(wps表格添加邊框線)
      下一篇:免費自動甘特圖
      相關(guān)文章
      国产亚洲av片在线观看播放 | 亚洲乱码一区av春药高潮| 久久亚洲精品无码观看不卡| 国产亚洲精品AAAA片APP| 91在线亚洲综合在线| avtt天堂网手机版亚洲| 亚洲色欲www综合网| 亚洲视频精品在线观看| 亚洲精品免费在线| 亚洲国产品综合人成综合网站| 亚洲福利一区二区精品秒拍| 亚洲无圣光一区二区| 亚洲国产精品久久久久秋霞影院| 亚洲视频国产精品| 亚洲成人黄色网址| 亚洲一区二区三区在线网站| 男人天堂2018亚洲男人天堂| 亚洲啪AV永久无码精品放毛片| 亚洲精品GV天堂无码男同| 久久亚洲精品高潮综合色a片| 在线观看亚洲专区| 亚洲国产人成精品| 亚洲日韩aⅴ在线视频| 久久精品亚洲视频| 亚洲美女中文字幕| 亚洲日韩乱码中文无码蜜桃臀| 亚洲六月丁香六月婷婷色伊人| 亚洲欧洲日韩极速播放| 亚洲国产av玩弄放荡人妇 | 亚洲五月六月丁香激情| 亚洲黄色在线网站| 亚洲jjzzjjzz在线播放| 亚洲人成网站在线播放2019| 国产成人高清亚洲一区久久| 亚洲伊人久久成综合人影院| 日韩亚洲一区二区三区| 在线免费观看亚洲| 亚洲熟女乱色一区二区三区| 国产偷国产偷亚洲高清人| 亚洲午夜久久久久久噜噜噜| 亚洲国产美国国产综合一区二区|