muduo源码学习(12)-日志类封装2
来源:互联网 发布:linux怎么重启服务器 编辑:程序博客网 时间:2024/06/08 02:28
之前大体上分析到muduo的日志的一些类,主要就是Logger类,该类的析构函数如下
//析构函数,输出日志Logger::~Logger(){//调用impl_的finish() impl_.finish(); const LogStream::Buffer& buf(stream().buffer());//调用输出g_output为函数指针 g_output(buf.data(), buf.length()); if (impl_.level_ == FATAL) { //刷新输出的缓冲区 g_flush(); abort(); }}
会调用函数指针g_output将日志输出到指定设备,默认的有
//默认的输出,输出到标准输出上void defaultOutput(const char* msg, int len){ size_t n = fwrite(msg, 1, len, stdout); //FIXME check n (void)n;}//默认的刷新,刷新stdoutvoid defaultFlush(){ fflush(stdout);}//默认的//OutputFunc//FlushFunc函数指针Logger::OutputFunc g_output = defaultOutput;Logger::FlushFunc g_flush = defaultFlush;}
可见默认日志是输出到标志输出设备上的。然而我们需要将日志保存到文件中,虽然可以重定向,但是还有解决日志滚动问题。也就是要限定每一个日志文件的大小,还有每天的日志文件的数量。muduo中封装了LogFile类来支持有关操作。在base/LogFile.h中
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_;//日志文件大小的上限, const size_t rollSize_;//刷新的间隔时间 const int flushInterval_;//¼ÆÊýÆ÷ int count_; boost::scoped_ptr<MutexLock> mutex_; //开始记录日志的时间(调整到零点) time_t startOfPeriod_;//上一次滚动的时间 time_t lastRoll_;//上一次刷新的时间 time_t lastFlush_; //File类前置声明 class File; // boost::scoped_ptr<File> file_; const static int kCheckTimeRoll_ = 1024; //一天的秒数 const static int kRollPerSeconds_ = 60*60*24;};
其中声明了一个File类,在base/LogFile.cc中
//class LogFile::File : boost::noncopyable{ public: explicit File(const string& filename) // : fp_(::fopen(filename.data(), "ae")), writtenBytes_(0) { assert(fp_);//设置缓冲区 ::setbuffer(fp_, buffer_, sizeof buffer_); // posix_fadvise POSIX_FADV_DONTNEED ? }// ~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://append() 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类中,比较重要的首先是获取日志文件名称
//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();//格式化进程id snprintf(pidbuf, sizeof pidbuf, ".%d", ProcessInfo::pid()); filename += pidbuf; filename += ".log"; return filename;}日志文件名称格式为 basename.时间.主机.进程号.log
写日志的操作
//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_; } }}
首先将日志写入文件 ,然后判断大小,是否要滚动日志,之后根据count_大小决定是否检查,判断当前时间与之前相比是否经过了一天,如果是,则滚动日志。其中
time_t thisPeriod_ = now / kRollPerSeconds_ * kRollPerSeconds_;
KRollPerSeconds是一天的秒数,now/KRollPerSeconds会把小数忽略,相当于同步到一天的零点,比如某天的4:30,会把4:30都舍弃,之后乘以kRollPerSeconds,得到秒数,如果在同一天,得到的结果是相同的,不会进行日志滚动。
日志滚动函数
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;//创建新的Filefile_.reset(new File(filename)); }}主要逻辑就是得到新的文件名称,创建新的文件,更新有关时间。
在使用写入到文件的日志的时候,需要设置Logger类中的函数指针,实例如下
boost::scoped_ptr<muduo::LogFile> g_logFile;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); g_logFile.reset(new muduo::LogFile(::basename(name), 200*1000)); muduo::Logger::setOutput(outputFunc); //设置函数指针 muduo::Logger::setFlush(flushFunc); muduo::string line = "1234567890 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ "; for (int i = 0; i < 10000; ++i) { LOG_INFO << line << i; usleep(1000); }
阅读全文
0 0
- muduo源码学习(12)-日志类封装2
- muduo源码学习(11)-日志类封装1
- muduo网络库源码学习————日志类封装
- muduo日志类的封装
- muduo源码学习(5)-线程封装
- muduo源码学习(19)-socket封装
- muduo源码学习(20)-Acceptor封装
- muduo源码分析:异常类封装
- muduo源码分析:线程类Thread封装
- muduo网络库学习笔记(8):高效日志类的封装
- muduo源码学习(15)-IO复用的封装
- muduo源码学习(2)-Timestamp
- muduo源码学习(1)
- muduo源码分析:日志相关类(1)
- muduo日志2
- muduo 日志库学习(一)
- muduo 日志库学习(二)
- muduo 日志库学习(二)
- Android Service使用方法--简单音乐播放实例
- 乐视秒杀:每秒十万笔交易的数据架构解读
- AsynTask
- 最小生成树-kruskal算法(克鲁斯卡尔算法)
- (敏感词匹配)将数据库的敏感词逗号隔开来进行内容匹配
- muduo源码学习(12)-日志类封装2
- LeetCode字符串(二)
- LeetCode 551. Student Attendance Record I (C++版)
- 穷举法:max-points-on-a-line
- 第一次写解压gz压缩文件,什么不对的地方或者待优化的地方劳烦指点指点,谢谢
- 2017世界人工智能企业排名
- C union使用
- MyBatis 延迟加载,一级缓存,二级缓存设置
- 类与对象