柚子快報(bào)邀請(qǐng)碼778899分享:c++ 【Linux】日志函數(shù)
柚子快報(bào)邀請(qǐng)碼778899分享:c++ 【Linux】日志函數(shù)
歡迎來(lái)到?破曉的歷程的 博客
??不負(fù)時(shí)光,不負(fù)己??
文章目錄
引言日志內(nèi)容日志等級(jí)日志函數(shù)的編寫(xiě)函數(shù)原型參數(shù)說(shuō)明功能描述使用場(chǎng)景示例代碼
引言
日志在程序設(shè)計(jì)中扮演著至關(guān)重要的角色,它不僅是程序運(yùn)行情況的記錄者,還是問(wèn)題診斷、性能優(yōu)化、安全審計(jì)以及用戶(hù)行為分析的重要工具。本篇博客我們就設(shè)計(jì)一個(gè)日志函數(shù),并在過(guò)程中學(xué)習(xí)一些知識(shí)。
日志內(nèi)容
一個(gè)完整的日志信息應(yīng)該包括:日志等級(jí)、時(shí)間、問(wèn)題描述、文件、行數(shù)等等。
日志等級(jí)
日志級(jí)別是對(duì)日志信息進(jìn)行分類(lèi)的一種方式。通過(guò)為日志信息分配不同的級(jí)別,開(kāi)發(fā)者可以更精細(xì)地控制日志的生成和輸出,從而在不同的場(chǎng)景下獲取最有價(jià)值的信息。常見(jiàn)的日志級(jí)別包括:
DEBUG:調(diào)試級(jí)別,用于輸出詳細(xì)的調(diào)試信息,通常在開(kāi)發(fā)和測(cè)試階段使用。NORMAL:信息級(jí)別,用于輸出一般性的信息,表示系統(tǒng)正常運(yùn)行。WARNING:警告級(jí)別,用于輸出可能的問(wèn)題或異常情況,但不會(huì)影響系統(tǒng)的正常運(yùn)行。ERROR:錯(cuò)誤級(jí)別,用于輸出嚴(yán)重的錯(cuò)誤信息,可能會(huì)影響系統(tǒng)的正常運(yùn)行。FATEL:嚴(yán)重錯(cuò)誤級(jí)別,用于輸出非常嚴(yán)重的錯(cuò)誤信息,通常會(huì)導(dǎo)致系統(tǒng)崩潰或無(wú)法繼續(xù)運(yùn)行。
#define DEBUG 1
#define NORMAL 2
#define WARNING 3
#define ERROR 4
#define FATEL 5
日志函數(shù)的編寫(xiě)
完整代碼為
#include
#include
#include
#include
#define DEBUG 1
#define NORMAL 2
#define WARNING 3
#define ERROR 4
#define FATEL 5
char *to_level(int level)
{
switch(level)
{
case 1:
return "DEBUG";
break;
case 2:
return "NORMAL";
break;
case 3:
return "WARNING";
break;
case 4:
return "ERROR";
break;
case 5:
return "FATEL";
break;
default:
return nullptr;
break;
}
}
void LogMessge(int level,const char *format,...)//"..."代表的是可變參數(shù)
{
//先將固定的部分格式化到logprefix中
char logprefix[1024];
snprintf(logprefix,sizeof(logprefix),"[%s][%ld][%d]",to_level(level),time(nullptr),getpid());
//然后將部分格式化到logcontent中
char logcontent[1024];
va_list argv;
va_start(argv,format);
vsnprintf(logcontent,sizeof(logcontent),format,argv);
std::cout< } 接下來(lái),我們對(duì)代碼講解一下: 可變參數(shù)列表 “…”代表是可變參數(shù)列表。 可變參數(shù)列表,顧名思義,就是函數(shù)的參數(shù)個(gè)數(shù)不是固定的,可以根據(jù)需要傳入任意數(shù)量的參數(shù)(但通常至少需要一個(gè)固定參數(shù)來(lái)指示后續(xù)可變參數(shù)的類(lèi)型或數(shù)量)。 例如: int printf(const char *format, ...); 特性: 至少需要一個(gè)固定參數(shù),這是為了函數(shù)能夠識(shí)別和處理后續(xù)的可變參數(shù)??勺儏?shù)部分在聲明時(shí)使用省略號(hào)(…)來(lái)表示??勺儏?shù)的類(lèi)型和數(shù)量在編譯時(shí)無(wú)法確定,通常需要在運(yùn)行時(shí)通過(guò)特定機(jī)制來(lái)訪問(wèn)和處理 如何實(shí)現(xiàn)可變參數(shù)列表呢? 在C語(yǔ)言中,可變參數(shù)列表的實(shí)現(xiàn)依賴(lài)于stdarg.h頭文件中的宏和類(lèi)型定義。這些宏和類(lèi)型允許開(kāi)發(fā)者在運(yùn)行時(shí)訪問(wèn)和處理可變參數(shù)。 va_list:這是一個(gè)類(lèi)型定義,用于聲明一個(gè)指向可變參數(shù)列表的指針。va_start:這是一個(gè)宏,用于初始化va_list類(lèi)型的變量,以便它可以指向函數(shù)的第一個(gè)可變參數(shù)。va_arg:這是一個(gè)宏,用于從va_list指向的位置提取下一個(gè)可變參數(shù),并更新va_list的指向,以便下一次提取。va_end:這是一個(gè)宏,用于結(jié)束對(duì)可變參數(shù)列表的訪問(wèn),并將va_list變量設(shè)置為無(wú)效狀態(tài)(通常是將其設(shè)置為NULL)。 vsnprintf vsnprintf函數(shù)是C語(yǔ)言標(biāo)準(zhǔn)庫(kù)中的一個(gè)函數(shù),它的作用是將格式化的數(shù)據(jù)寫(xiě)入一個(gè)字符串緩沖區(qū)中,同時(shí)允許指定緩沖區(qū)的大小,以防止緩沖區(qū)溢出。這個(gè)函數(shù)在C99及以后的版本中得到了廣泛的支持,也在C++11及以后的版本中可用。 函數(shù)原型 vsnprintf函數(shù)的原型如下: int vsnprintf(char *str, size_t size, const char *format, va_list ap); 參數(shù)說(shuō)明 str:指向字符緩沖區(qū)的指針,用于存儲(chǔ)格式化后的字符串。size:指定緩沖區(qū)的大小,即最多可以存儲(chǔ)多少個(gè)字符(包括終止的空字符’\0’)。這有助于防止緩沖區(qū)溢出。format:格式字符串,用于指定后續(xù)參數(shù)如何被格式化和插入到輸出字符串中。這個(gè)字符串可以包含普通的字符和格式說(shuō)明符(如%d、%s等)。ap:一個(gè)va_list類(lèi)型的參數(shù),它代表了一個(gè)可變參數(shù)列表。這個(gè)列表包含了要被格式化的實(shí)際參數(shù)。 功能描述 vsnprintf函數(shù)會(huì)讀取格式字符串format,并根據(jù)格式說(shuō)明符從可變參數(shù)列表ap中檢索相應(yīng)的參數(shù)進(jìn)行格式化。格式化后的字符串(或其中的一部分,如果它太長(zhǎng)而無(wú)法完全適應(yīng)緩沖區(qū))會(huì)被寫(xiě)入到str指向的緩沖區(qū)中。如果生成的字符串長(zhǎng)度小于size,則會(huì)在字符串末尾添加一個(gè)空字符’\0’作為結(jié)束符。如果生成的字符串長(zhǎng)度大于或等于size,則只將size-1個(gè)字符寫(xiě)入緩沖區(qū)(不包括空字符),并且不會(huì)在緩沖區(qū)末尾添加空字符。此外,函數(shù)會(huì)返回一個(gè)整數(shù),表示如果不考慮緩沖區(qū)大小限制,格式化后的字符串應(yīng)該包含的字符數(shù)(不包括空字符)。 使用場(chǎng)景 vsnprintf函數(shù)特別適用于那些需要嚴(yán)格控制輸出緩沖區(qū)大小的情況,比如嵌入式系統(tǒng)編程、網(wǎng)絡(luò)編程等。在這些場(chǎng)景下,緩沖區(qū)溢出可能會(huì)導(dǎo)致嚴(yán)重的后果,如程序崩潰、數(shù)據(jù)損壞或安全漏洞。通過(guò)使用vsnprintf函數(shù),開(kāi)發(fā)者可以確保即使在最壞的情況下,也不會(huì)發(fā)生緩沖區(qū)溢出。 示例代碼 以下是一個(gè)使用vsnprintf函數(shù)的示例代碼: #include #include void MyPrintF(char *buffer, size_t bufferSize, const char *format, ...) { va_list args; va_start(args, format); vsnprintf(buffer, bufferSize, format, args); va_end(args); // 注意:如果bufferSize足夠大,并且需要字符串以'\0'結(jié)尾, // 則可能需要在調(diào)用vsnprintf后手動(dòng)添加'\0', // 但在這個(gè)例子中,由于我們使用了bufferSize作為限制, // 如果字符串被截?cái)啵瑒t不需要添加'\0'(因?yàn)閎uffer的其余部分未定義)。 // 如果需要確保buffer以'\0'結(jié)尾,并且確信bufferSize足夠大, // 可以在調(diào)用vsnprintf之前將buffer[0]設(shè)置為'\0', // 或者在調(diào)用后(如果確定沒(méi)有溢出)將buffer[bufferSize-1]設(shè)置為'\0'。 // 但在這個(gè)簡(jiǎn)單的示例中,我們假設(shè)調(diào)用者會(huì)正確處理buffer。 printf("%s\n", buffer); } int main() { char buffer[100]; MyPrintF(buffer, sizeof(buffer), "Hello, %s! You are %d years old.", "Alice", 30); return 0; } 在這個(gè)示例中,我們定義了一個(gè)MyPrintF函數(shù),它接受一個(gè)緩沖區(qū)、緩沖區(qū)的大小、一個(gè)格式字符串和可變數(shù)量的參數(shù)。然后,它使用vsnprintf函數(shù)將這些參數(shù)格式化并寫(xiě)入緩沖區(qū),并通過(guò)printf函數(shù)打印出來(lái)。注意,在實(shí)際應(yīng)用中,我們可能需要更仔細(xì)地處理緩沖區(qū)的大小和終止的空字符。 接下來(lái),我們模擬實(shí)現(xiàn)printf函數(shù) #include #include #include void my_printf(const char* format, ...) { va_list args; va_start(args, format); char buffer[1024]; vsnprintf(buffer, sizeof(buffer), format, args); std::cout << buffer << std::endl; } int main() { int cnt = 12; my_printf("%d", cnt); } 但是這個(gè)日志函數(shù)太復(fù)雜,有沒(méi)有簡(jiǎn)單一點(diǎn)的? 有而且一個(gè)宏就可以搞定。 具體請(qǐng)看這篇博客:日志函數(shù)的簡(jiǎn)單方法 柚子快報(bào)邀請(qǐng)碼778899分享:c++ 【Linux】日志函數(shù) 相關(guān)文章
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。