【高效server實踐】--日誌模塊

log日誌模塊是軟件程序的另一基礎部分,開發者依賴於它進行debug,瞭解程序運行狀態,分析程序性能等,是程序對開發都打開的一扇窗戶
一個健壯的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);

   }



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章