一個健壯的log模塊,應該具體以下功能
1:log可分級輸出
log一般有五層分級即可:debug,info,warn,error,trace
debug是用於開發者調試輸出的記錄,通過此開發者可以快速定位問題
info是記錄程序輸入,輸出和一些關鍵業務或路徑信息,通過此可以整體業務邏輯
warn表明會出現潛在的錯誤
trace就用於記錄程序的執行信息
2:log輸出以格式化的形式(類似snprintf):LOG_DBG("reconnect redis success,ip:%s,port:%d",server_ip,server_port);這裏參數可變(0到n個),c++裏面可以使用以下形式實現:
char arrLogline[1024];
va_list arg_ptr;//va_list是一個字符指針,可以理解爲指向當前參數的一個指針,取參必須通過這個指針進行
va_start(arg_ptr, sz Format);//將參數指針指向szFormat開始
vsnprintf(arrLogline, sizeof(s_szBuff), szFormat,arg_ptr);//格式化輸出szFormat參數之後的參數
· va_end(arg_ptr);//清空參數列表,並置參數指針ap無效
3:可以配置打印哪些級別的日誌,如開發線可以答應TRACE和DEBUG日誌,生產線就無需打印
log級別配置:ERR|WARN|INFO|DBG|TRACE
uint32_t LOG_LEVEL_ERR=1,LOG_LEVEL_WARN=2,LOG_LEVEL_INFO=4,LOG_LEVEL_DBG=8,LOG_LEVEL_TRACE=16;
uint32_t dwLevelSet = 0;
const char *aszLevel[]={
"ERR",
"WARN",
"INFO",
"DBG",
"TRACE"
};
const uint32_t adwLevel[]={
LOG_LEVEL_ERR,
LOG_LEVEL_WARN,
LOG_LEVEL_INFO,
LOG_LEVEL_DBG,
LOG_LEVEL_TRACE
};
for (int i = 0; i < (int)sizeof(adwLevel)/(int)sizeof(adwLevel[0]); i++)
{
ifaszLevelvel.find(aszLevel[i]) != string::npos)
{
dwLevelSet |= adwLevel[i];
}
}
4:log文件限制大小,超限則分文件可配置每天可以打多少個log文件,文件大小最大爲多少。每次打log都判斷下文件大小是否超限,以便調整log打印至新文件
int lMaxSize=1024*x1024*100;//單文件最大100M
int lMaxFileCnt=100;//每天最多一個百個log文件
struct stat stStat;
FILE* fileHandle=NULL;
char newFilename[128]={0};
if ((fileHandle = fopen(filename, "a+")) == NULL)
return -1;
if(fstat(fileno(fileHandle ), &stStat) < 0) // stat -> fstat, modified by augustzhang,
{ // 修正多進程同時打LOG 導致文件過大core down的問題
fclose(fileHandle );
fileHandle = NULL;
return -1;
}
` if (stStat.st_size < lMaxSize) return 0;
for (i = 0; i <= lMaxFileCnt; ++i)
{
if (i == 0)
sprintf(newFilename,"%s.log",filename);
else
sprintf(newFilename,"%s_%d.log", filename, i);
if (access(newFilename, F_OK) != 0)
{
break;
}
}
if ((fileHandle = fopen(newFilename, "a+")) == NULL)
return -1;
5:log行信息可以定位到哪個文件,哪個函數,哪一行打印的。
使用宏定義的方法和預定義的宏,c++裏面是這樣實現的
#define LOG_DBG(messgae) fileHandle<< __FILE__<<":"<<__LINE__<<":"<<__FUNCTION__<<std::endl;
#inluce<fstream>
extern std::ofstream fileHandle;
6:log打印的時間可以精確到毫秒或微妙級別
在C++時裏面,可以通過以下方式獲取精確到微妙級別的時間
struct timeval stLogtime;
gettimeofday(&stLogtime, NULL);
fprintf(fileHandle, "[%s.%.6d]",GetCurDateTimeStr(), (int)stLogtime.tv_usec);
char* GetCurDateTimeStr(){
time_t mytime = time(NULL);
static char s[50] = {0};
struct tm curr = *localtime(mytime);
if (curr.tm_year > 50)
sprintf(s, "%04d-%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);
else
sprintf(s, "%04d-%02d-%02d %02d:%02d:%02d",
curr.tm_year+2000, curr.tm_mon+1, curr.tm_mday,
curr.tm_hour, curr.tm_min, curr.tm_sec);
}