muduo庫源碼學習(base):Logfile

本文件使用的是C++17版本

#ifndef MUDUO_BASE_LOGFILE_H
#define MUDUO_BASE_LOGFILE_H

#include <muduo/base/Mutex.h>
#include <muduo/base/Types.h>

#include <memory>

namespace muduo
{

namespace FileUtil
{
class AppendFile;
}

class LogFile : noncopyable//文件日誌類
{
 public:
  LogFile(const string& basename,
          size_t rollSize,
          bool threadSafe = true,
          int flushInterval = 3,
          int checkEveryN = 1024);
  ~LogFile();

  void append(const char* logline, int len);
  void flush();
  bool rollFile();//生成新日誌文件

 private:
  void append_unlocked(const char* logline, int len);
  //如果打算開闢新文件,根據basename和當前時間,得到意圖創建的文件名字
  static string getLogFileName(const string& basename, time_t* now);

  const string basename_;
  const size_t rollSize_;//日誌文件的極限容量,超過後,將導致開闢新文件
  const int flushInterval_;
  const int checkEveryN_;

  int count_;

  std::unique_ptr<MutexLock> mutex_;
  time_t startOfPeriod_;
  time_t lastRoll_;//記錄文件創建時間
  time_t lastFlush_;//記錄上次刷新時間
  std::unique_ptr<FileUtil::AppendFile> file_;

  const static int kRollPerSeconds_ = 60*60*24;//刷新時間
};

}
#endif  // MUDUO_BASE_LOGFILE_H

#include <muduo/base/LogFile.h>

#include <muduo/base/FileUtil.h>
#include <muduo/base/ProcessInfo.h>

#include <assert.h>
#include <stdio.h>
#include <time.h>

using namespace muduo;

LogFile::LogFile(const string& basename,
                 size_t rollSize,
                 bool threadSafe,
                 int flushInterval,
                 int checkEveryN)
  : basename_(basename),
    rollSize_(rollSize),
    flushInterval_(flushInterval),
    checkEveryN_(checkEveryN),
    count_(0),
    mutex_(threadSafe ? new MutexLock : NULL),//是否要求線程安全
    startOfPeriod_(0),
    lastRoll_(0),
    lastFlush_(0)
{
  assert(basename.find('/') == string::npos);//文件名裏沒有古怪的符號
  rollFile();
}

LogFile::~LogFile()
{
}

void LogFile::append(const char* logline, int len)
{
  if (mutex_)//沒有必要專寫一個加鎖版本
  {
    MutexLockGuard lock(*mutex_);
    append_unlocked(logline, len);
  }
  else
  {
    append_unlocked(logline, len);
  }
}

void LogFile::flush()//立刻寫到文件
{
  if (mutex_)
  {
    MutexLockGuard lock(*mutex_);
    file_->flush();
  }
  else
  {
    file_->flush();
  }
}

void LogFile::append_unlocked(const char* logline, int len)//具體的追加函數
{
  file_->append(logline, len);//先寫入

  if (file_->writtenBytes() > rollSize_)//如果超出滾動臨界大小,則滾動文件
  {
    rollFile();
  }
  else
  {
    ++count_;//追寫次數
    if (count_ >= checkEveryN_)//追寫次數超過指定次數
    {
      count_ = 0;//清零。也就是說,追寫次數和文件大小共同決定了日誌滾動
      time_t now = ::time(NULL);
      time_t thisPeriod_ = now / kRollPerSeconds_ * kRollPerSeconds_;//time_t就是個long int,這裏把天數的餘數清除掉
      if (thisPeriod_ != startOfPeriod_)//不是同一天
      {
        rollFile();//滾動日誌文件
      }
      else if (now - lastFlush_ > flushInterval_)//達到刷新間隔
      {
        lastFlush_ = now;
        file_->flush();//寫文件
      }
    }
  }
}

bool LogFile::rollFile()//嘗試滾動文件,對時間再檢查一次
{
  time_t now = 0;
  string filename = getLogFileName(basename_, &now);//得到文件名和當前時間
  time_t start = now / kRollPerSeconds_ * kRollPerSeconds_;//保存1970到現在經過的天數

  if (now > lastRoll_)//這不應該有誤
  {
    lastRoll_ = now;//滾動時間
    lastFlush_ = now;//刷新時間
    startOfPeriod_ = start;//創建時間(天)
    file_.reset(new FileUtil::AppendFile(filename));//重新設置一個可追加的文件
    return true;
  }
  return false;//不應該發生
}

string LogFile::getLogFileName(const string& basename, time_t* now)
{
  string filename;
  filename.reserve(basename.size() + 64);
  filename = basename;

  char timebuf[32];
  struct tm tm;
  *now = time(NULL);
  gmtime_r(now, &tm); // FIXME: localtime_r ?
  strftime(timebuf, sizeof timebuf, ".%Y%m%d-%H%M%S.", &tm);
  filename += timebuf;//文件名+日期

  filename += ProcessInfo::hostname();//再加上主機名

  char pidbuf[32];
  snprintf(pidbuf, sizeof pidbuf, ".%d", ProcessInfo::pid());
  filename += pidbuf;//再加上線程id

  filename += ".log";//尾綴

  return filename;
}



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