muduo库源码学习(base):Logfile

16 篇文章 0 订阅

本文件使用的是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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值