muduo原始碼解析14-logfile類
阿新 • • 發佈:2020-08-25
logfile類:
class logfile:noncopyable { };
作用:
主要負責日誌寫入檔案的管理
內部提供append,rollFile,flush三個函式
append表示向檔案尾部追加資料,
rollFile表示需要更換一個日誌檔案來寫日誌
flush表示清空檔案讀寫緩衝區
注意append和flush都提供了有鎖/無鎖的實現,logfile建構函式需要傳入是否是執行緒安全的threadSafe引數
若是true需要建立一個互斥所mutexlock並且加鎖,否則不用加鎖.
logfile成員變數:
private: const string m_basename; //日誌檔名 const off_t m_rollSize; //已寫入的資料大於rollsize就生成一個新日誌檔案 const int m_flushInterval; //日誌寫入時間間隔,預設每3s寫一次 const int m_checkEveryN; //m_count>預設=1024時需要檢查是否回滾或寫入 int m_count; //計數器,每次append操作時,都需要讓m_count++更新 std::unique_ptr<mutexlock> m_mutex;//鎖智慧指標 time_t m_startOfPeriod; //開始記錄日誌的時間 time_t m_lastRoll; //上一次滾動日誌檔案的時間 time_t m_lastFlush; //上一次日誌寫入檔案的時間 std::unique_ptr<fileutil::AppendFile> m_file; //檔案智慧指標 static const int m_kRollPerSeconds=60*60*24; //一天的秒數
logfile成員函式:
public: logfile(const string& basename,off_t rollSize,bool threadSafe=true, int flushInterval=3,int checkEveryN=1024); ~logfile(); //寫檔案操作,有鎖/無鎖兩種實現 void append(const char* logline,int len); //清空檔案讀寫緩衝區,有鎖/無鎖兩種實現 void flush(); //回滾檔案,其實就是當前檔案不能寫日誌了,需要更換下一個日誌檔案來寫日誌 bool rollFile(); private: //append的實現函式 void append_unlocked(const char* logline,int len); //根據當前時間獲得一個新的日誌檔名字 static string getLogFileName(const string& basename,time_t* now);
logfile.h
#ifndef LOGFILE_H #define LOGFILE_H #include"base/mutex.h" #include"base/types.h" #include<memory> namespace mymuduo { namespace fileutil{ class AppendFile; } class logfile:noncopyable { public: logfile(const string& basename,off_t rollSize,bool threadSafe=true, int flushInterval=3,int checkEveryN=1024); ~logfile(); //寫檔案操作,有鎖/無鎖兩種實現 void append(const char* logline,int len); //清空檔案讀寫緩衝區,有鎖/無鎖兩種實現 void flush(); //回滾檔案,其實就是當前檔案不能寫日誌了,需要更換下一個日誌檔案來寫日誌 bool rollFile(); private: //append的實現函式 void append_unlocked(const char* logline,int len); //根據當前時間獲得一個新的日誌檔名字 static string getLogFileName(const string& basename,time_t* now); const string m_basename; //日誌檔名 const off_t m_rollSize; //已寫入的資料大於rollsize就生成一個新日誌檔案 const int m_flushInterval; //日誌寫入時間間隔,預設每3s寫一次 const int m_checkEveryN; //m_count>預設=1024時需要檢查是否回滾或寫入 int m_count; //計數器,每次append操作時,都需要讓m_count++更新 std::unique_ptr<mutexlock> m_mutex;//鎖智慧指標 time_t m_startOfPeriod; //開始記錄日誌的時間 time_t m_lastRoll; //上一次滾動日誌檔案的時間 time_t m_lastFlush; //上一次日誌寫入檔案的時間 std::unique_ptr<fileutil::AppendFile> m_file; //檔案智慧指標 static const int m_kRollPerSeconds=60*60*24; //一天的秒數 }; }//namespace mymuduo #endif // LOGFILE_H
logfile.cpp
#include "logfile.h" #include"base/fileutil.h" #include"base/processinfo.h" #include<assert.h> #include<stdio.h> #include<time.h> namespace mymuduo { //建構函式,負責初始化檔名,回滾大小,是否執行緒安全(判斷是否需要建立互斥鎖), //寫入日誌檔案的時間間隔等資訊 logfile::logfile(const string& basename,off_t rollSize,bool threadSafe, int flushInterval,int checkEveryN) :m_basename(basename),m_rollSize(rollSize),m_flushInterval(flushInterval), m_checkEveryN(checkEveryN),m_count(0), m_mutex(threadSafe?new mutexlock:NULL), m_startOfPeriod(0),m_lastRoll(0),m_lastFlush(0) { //保證basename中沒有 / , 也就是這裡basename是檔名而不是檔案路徑 assert(basename.find('/')==string::npos); rollFile(); } logfile::~logfile()=default; //兩種方式:有鎖/無鎖,內部都是append_unlocked()函式實現 void logfile::append(const char* logline,int len) { if(!m_mutex) append_unlocked(logline,len); else { mutexlockguard mlg(*m_mutex); append_unlocked(logline,len); } } //兩種方式:有鎖/無鎖,內部都是AppendFile::flush()實現 void logfile::flush() { if(!m_mutex) m_file->flush(); else { mutexlockguard mlg(*m_mutex); m_file->flush(); } } //回滾日誌檔案,功能是根據當前時間now設定m_lastRoll,m_lastFlush,m_startOfPeriod //並把m_file重新指向一個新的AppendFile(完整日誌檔名字) bool logfile::rollFile() { time_t now = 0; //filename格式 test.txt.20200825-064633.master.22895.log string filename = getLogFileName(m_basename, &now); time_t start = now / m_kRollPerSeconds * m_kRollPerSeconds;//啥意思? //這裡考慮一下now<=m_lastRoll,要不然就是getLogFileName返回錯誤的now //要不然就是時間靜止/倒退,肯定不正確,只考慮now>m_lastRoll if (now > m_lastRoll) { m_lastRoll = now; m_lastFlush = now; m_startOfPeriod = start; //m_file重新指向一個新的AppendFile物件,開啟的檔案為filename //即完整的日誌檔名字,如果檔案不存在則新建立一個檔案 m_file.reset(new fileutil::AppendFile(filename)); return true; } return false; } //利用AppendFile類完成向檔案中寫操作 void logfile::append_unlocked(const char* logline,int len) { //向檔案中寫入長度為len的logline字串 m_file->append(logline,len); //判斷已寫入的位元組數是否超出了回滾大小,若超出了只能再次回滾檔案: //根據當前時間建立一個新的日誌檔案,並且把m_file指向這個新的AppendFile if(m_file->writtenBytes()>m_rollSize) rollFile(); else { //不需要回滾檔案時候,對當前檔案進行操作即可. m_count++; if(m_count>=m_checkEveryN) { //此時重置m_count,再次回滾檔案. m_count=0; time_t now=::time(NULL); time_t thisPeriod=now/m_kRollPerSeconds*m_kRollPerSeconds; if(thisPeriod!=m_startOfPeriod) //比較是否相等,不相等 說明到了第二天0點,就滾動檔案 rollFile(); else if(now-m_lastFlush>m_flushInterval)//判斷是否超過flush時間間隔 { m_lastFlush=now; m_file->flush(); } } } } //得到完整的日誌檔名字,例如basename=test.txt時,filename=如下 //test.txt.20200825-064633.master.22895.log //basename.時間.hostname.pid.log //就是一個完整的日誌檔名字 string logfile::getLogFileName(const string& basename,time_t* now) { string filename; filename.reserve(basename.size()+64); //新增basename filename=basename; char timebuf[32]; struct tm tm; *now=::time(NULL); gmtime_r(now,&tm); strftime(timebuf, sizeof timebuf, ".%Y%m%d-%H%M%S.", &tm); filename += timebuf; //新增time filename+=processinfo::hostname();//新增hostname char pidbuf[32]; snprintf(pidbuf, sizeof pidbuf, ".%d", processinfo::pid()); filename += pidbuf;//新增pid filename += ".log";//新增字尾名 return filename; } }