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;
}