日志滚动
日志滚动条件
1、文件大小(例如每写满1G换下一个文件)
2、时间(每天零点新建一个日志文件,不论前一个文件是否写满)
一个典型的日志文件名
logfile_test.20130411-115604.popo.7743.log
Logger 类图
File类图
file类是LogFile的一个内置类
LogFile头文件(logfile.h)
#ifndef MUDUO_BASE_LOGFILE_H #define MUDUO_BASE_LOGFILE_H #include <muduo/base/Mutex.h> #include <muduo/base/Types.h> #include <boost/noncopyable.hpp> #include <boost/scoped_ptr.hpp> namespace muduo { class LogFile : boost::noncopyable { public: LogFile(const string& basename, size_t rollSize, bool threadSafe = true, int flushInterval = 3); ~LogFile(); void append(const char* logline, int len); void flush(); private: void append_unlocked(const char* logline, int len); static string getLogFileName(const string& basename, time_t* now); //获取日志文件路径 void rollFile(); //滚动日志 const string basename_; //日志文件basename const size_t rollSize_; //日志文件达到 rolSize_ 换一个新文件 const int flushInterval_; //日志文件写入间隔时间 ,不是每一次的日志都直接写入文件,这样也有助于提高效率 int count_; //计数器 ,当达到kCheckTimeRoll_时,会去检测是否要滚动日志文件 boost::scoped_ptr<MutexLock> mutex_; time_t startOfPeriod_; //开始记录日志时间(调整至零点) time_t lastRoll_; //上一次滚动日志文件时间 time_t lastFlush_;//上一次日志写入文件时间 class File; //日志文件类 boost::scoped_ptr<File> file_; //日子文件指针,这是一个智能指针 const static int kCheckTimeRoll_ = 1024; // const static int kRollPerSeconds_ = 60*60*24; //一天 }; } #endif // MUDUO_BASE_LOGFILE_H
LogFile的源文件
#include <muduo/base/LogFile.h> #include <muduo/base/Logging.h> // strerror_tl #include <muduo/base/ProcessInfo.h> #include <assert.h> #include <stdio.h> #include <time.h> using namespace muduo; // not thread safe 不是线程安全 class LogFile::File : boost::noncopyable //不可复制 { public:、 /******** //File 类 **********/ explicit File(const string& filename) : fp_(::fopen(filename.data(), "ae")), writtenBytes_(0) { assert(fp_); //断言fp_指针是否为空 ::setbuffer(fp_, buffer_, sizeof buffer_); //是指缓冲区的大小 // posix_fadvise POSIX_FADV_DONTNEED ? } //虚构函数 , 关闭fp_指针 ~File() { ::fclose(fp_); } //追加 日志 void append(const char* logline, const size_t len) { size_t n = write(logline, len); size_t remain = len - n; while (remain > 0) { size_t x = write(logline + n, remain); if (x == 0) { int err = ferror(fp_); if (err) { fprintf(stderr, "LogFile::File::append() failed %s\n", strerror_tl(err)); } break; } n += x; remain = len - n; // remain -= x } writtenBytes_ += len; } //清空缓冲区 void flush() { ::fflush(fp_); } size_t writtenBytes() const { return writtenBytes_; } private: //不加锁写入文件,logfile已经加锁了 size_t write(const char* logline, size_t len) { #undef fwrite_unlocked return ::fwrite_unlocked(logline, 1, len, fp_); } FILE* fp_; char buffer_[64*1024]; size_t writtenBytes_; }; /******* LogFile类 *******/ LogFile::LogFile(const string& basename, size_t rollSize, bool threadSafe, int flushInterval) : basename_(basename),//文件basename rollSize_(rollSize),//日志滚动大小界限 flushInterval_(flushInterval), //清空缓冲区 count_(0), mutex_(threadSafe ? new MutexLock : NULL),//是否以线程安全的方式进行操作 startOfPeriod_(0), lastRoll_(0), lastFlush_(0) { //断言 ,basename 是否包含"/" 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 { //时间上测试 ,就是计数器 if (count_ > kCheckTimeRoll_) { count_ = 0; time_t now = ::time(NULL); time_t thisPeriod_ = now / kRollPerSeconds_ * kRollPerSeconds_; if (thisPeriod_ != startOfPeriod_) { rollFile(); } //是否应该清空数据 else if (now - lastFlush_ > flushInterval_) { lastFlush_ = now; file_->flush(); } } //计数器++ else { ++count_; } } } //日志滚动 void LogFile::rollFile() { time_t now = 0; string filename = getLogFileName(basename_, &now); time_t start = now / kRollPerSeconds_ * kRollPerSeconds_; //如果是时间上的滚动,那么就要更新一下时间了 if (now > lastRoll_) { lastRoll_ = now; lastFlush_ = now; startOfPeriod_ = start; file_.reset(new File(filename)); } } //得到日志文件名 string LogFile::getLogFileName(const string& basename, time_t* now) { string filename; filename.reserve(basename.size() + 64); filename = basename; char timebuf[32]; char pidbuf[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(); snprintf(pidbuf, sizeof pidbuf, ".%d", ProcessInfo::pid()); filename += pidbuf; filename += ".log"; return filename; }
LogFile测试类 LogFile_Test.cc
#include <muduo/base/LogFile.h> #include <muduo/base/Logging.h> boost::scoped_ptr<muduo::LogFile> g_logFile; //msg日志内容,日志长度 void outputFunc(const char* msg, int len) { g_logFile->append(msg, len); } void flushFunc() { g_logFile->flush(); } int main(int argc, char* argv[]) { char name[256]; strncpy(name, argv[0], 256); //日志滚动的大小200*1000 = 196k g_logFile.reset(new muduo::LogFile(::basename(name), 200*1000)); //Logger的输出函数 muduo::Logger::setOutput(outputFunc); //Logger的缓冲区清空函数 muduo::Logger::setFlush(flushFunc); //日志 muduo::string line = "1234567890 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ "; //10000条日志记录 for (int i = 0; i < 10000; ++i) { LOG_INFO << line << i; usleep(1000); } }
程序输出:
[root@localhost bin]# ls -lh logfile_test* -rwxr-xr-x. 1 root root 610K Oct 17 16:02 logfile_test -rw-r--r--. 1 root root 196K Oct 17 16:03 logfile_test.20131017-080304.localhost.localdomain.2656.log -rw-r--r--. 1 root root 196K Oct 17 16:03 logfile_test.20131017-080309.localhost.localdomain.2656.log -rw-r--r--. 1 root root 196K Oct 17 16:03 logfile_test.20131017-080312.localhost.localdomain.2656.log -rw-r--r--. 1 root root 196K Oct 17 16:03 logfile_test.20131017-080314.localhost.localdomain.2656.log -rw-r--r--. 1 root root 196K Oct 17 16:03 logfile_test.20131017-080316.localhost.localdomain.2656.log -rw-r--r--. 1 root root 196K Oct 17 16:03 logfile_test.20131017-080319.localhost.localdomain.2656.log -rw-r--r--. 1 root root 87K Oct 17 16:03 logfile_test.20131017-080321.localhost.localdomain.2656.log [root@localhost bin]#