muduo之LogFile,LogFile是控制日誌怎麼和文件打交道,其中包含常用的對日誌處理的一些操作。AsyncLogging異步日誌需要調用LogFile的接口將日誌寫入文件,其中包含了AppendFile類,相當於再AppendFile上面封裝了一層。
LogFile.h
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#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,
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:
void append_unlocked(const char* logline, int len); //不加鎖的append方式
static string getLogFileName(const string& basename, time_t* now); //獲取日誌文件的名稱
const string basename_; //日誌文件basename
const off_t rollSize_; //日誌文件達到rolsize生成一個新文件
const int flushInterval_; //日誌寫入間隔時間
const int checkEveryN_; // 每調用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; //即時間一天
};
} // namespace muduo
#endif // MUDUO_BASE_LOGFILE_H
LogFile.cc
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#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,
off_t rollSize,
bool threadSafe,
int flushInterval,
int checkEveryN)
: basename_(basename),
rollSize_(rollSize),
flushInterval_(flushInterval),
checkEveryN_(checkEveryN),
count_(0),
mutex_(threadSafe ? new MutexLock : NULL), //不是線程安全就不需要構造mutex_
startOfPeriod_(0),
lastRoll_(0),
lastFlush_(0)
{
assert(basename.find('/') == string::npos); //斷言basename不包含'/'
rollFile();
}
LogFile::~LogFile() = default;
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)//不加鎖的append方式
{
file_->append(logline, len);//AppendFile->append
if (file_->writtenBytes() > rollSize_)
{
rollFile();
}
else
{
++count_;
if (count_ >= checkEveryN_)
{
count_ = 0;
time_t now = ::time(NULL);
time_t thisPeriod_ = now / kRollPerSeconds_ * kRollPerSeconds_;//比較事件是否相等,不等就是第二天0點,那麼滾動
if (thisPeriod_ != startOfPeriod_)
{
rollFile();
}
else if (now - lastFlush_ > flushInterval_)//判斷是否超過flush間隔時間,超過了就flush,否則什麼都不做
{
lastFlush_ = now;
file_->flush();
}
}
}
}
bool LogFile::rollFile()//滾動
{
time_t now = 0;
string filename = getLogFileName(basename_, &now);////獲取生成一個文件名稱
//注意,這裏先除KRollPerSeconds然後乘KPollPerSeconds表示對齊值KRollPerSeconds的整數倍,也就是事件調整到當天零點(/除法會引發取整)
time_t start = now / kRollPerSeconds_ * kRollPerSeconds_;
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 ? //獲取當前時間,UTC時間,_r是線程安全
strftime(timebuf, sizeof timebuf, ".%Y%m%d-%H%M%S.", &tm);//格式化時間,strftime函數
filename += timebuf;
filename += ProcessInfo::hostname();
char pidbuf[32];
snprintf(pidbuf, sizeof pidbuf, ".%d", ProcessInfo::pid());
filename += pidbuf;
filename += ".log";
return filename;
}