LogFile类:
1、在介绍Logger类时,我们提到Logger类可以自定义Output xx函数和Flush xx函数,由用户来选择日志信息的输出位置以及flush方式,例如在muduo库学习笔记十三:base库之日志库一 Logger类示例程序中,我们就使用fwrite和fflush作为日志信息输出方法。而LogFile类就相当于定义了Muduo库自己的输出到日志文件的Output和Flush函数。
2、LogFile类定义了日志滚动的规则,可以根据用户传入参数进行定制。首先根据日志大小进行滚动,其次根据时间进行滚动。此外,日志信息不是直接输出到文件,是先到缓冲区,再由缓冲区输出到文件,LogFile类也定义了缓冲区flush的时间间隔。
类图:
知识点:
1、append_unlocked函数调用File类中的append函数进行缓冲区写入,并对日志文件滚动以及缓冲区flush进行控制。
2、 time_t startOfPeriod_; // 开始记录日志时间(调整至当天零点距离1970年1月1号的秒数)--方便下次滚动日志时进行比较
3、LogFile类可以选择是否采用线程安全版本,非线程安全版本效率高4、void LogFile::rollFile()函数 time_t start = now / kRollPerSeconds_ * kRollPerSeconds_;
这里先除kRollPerSeconds_ 后乘kRollPerSeconds_表示对齐至kRollPerSeconds_整数倍,也就是时间调整到当天零点。
示例1:
#include <muduo/base/LogFile.h>
#include <muduo/base/Logging.h>
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));
/*
成员函数void reset(T * p = 0):成员函数reset()的功能是重置scoped_ptr,它删除原来保存的指针,
再保存新的指针值p。如果p是空指针,那么scoped_ptr将不持有任何指针。
*/
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);
}
}
该例子是将指定内容输入到目标文件中,通过LogFile类使用指定的滚动策略进行记录。
示例2:
#include <muduo/base/Logging.h>
#include <muduo/base/LogFile.h>
#include <muduo/base/ThreadPool.h>
#include <stdio.h>
int g_total;
FILE* g_file;
boost::scoped_ptr<muduo::LogFile> g_logFile;
void dummyOutput(const char* msg, int len)
{
g_total += len;
if (g_file)
{
fwrite(msg, 1, len, g_file);
}
else if (g_logFile)
{
g_logFile->append(msg, len);
}
}
void bench(const char* type)//性能测试
{
muduo::Logger::setOutput(dummyOutput);
muduo::Timestamp start(muduo::Timestamp::now());
g_total = 0;
int n = 1000*1000;
const bool kLongLog = false;
muduo::string empty = " ";
muduo::string longStr(3000, 'X');
longStr += " ";
for (int i = 0; i < n; ++i)
{
LOG_INFO << "Hello 0123456789" << " abcdefghijklmnopqrstuvwxyz"
<< (kLongLog ? longStr : empty)
<< i;
}
muduo::Timestamp end(muduo::Timestamp::now());
double seconds = timeDifference(end, start);
printf("%12s: %f seconds, %d bytes, %10.2f msg/s, %.2f MiB/s\n",
type, seconds, g_total, n / seconds, g_total / seconds / (1024 * 1024));
}
void logInThread()
{
LOG_INFO << "logInThread";//输出到标准输出
usleep(1000);
}
int main()
{
getppid(); // for ltrace and strace
//线程池
muduo::ThreadPool pool("pool");
pool.start(5);//启动5个线程
pool.run(logInThread);//线程池中的线程运行5个任务
pool.run(logInThread);
pool.run(logInThread);
pool.run(logInThread);
pool.run(logInThread);
//主线程
LOG_TRACE << "trace";//主线程输出
LOG_DEBUG << "debug";
LOG_INFO << "Hello";
LOG_WARN << "World";
LOG_ERROR << "Error";
LOG_INFO << sizeof(muduo::Logger);
LOG_INFO << sizeof(muduo::LogStream);
LOG_INFO << sizeof(muduo::Fmt);
LOG_INFO << sizeof(muduo::LogStream::Buffer);
sleep(1);
bench("nop");
char buffer[64*1024];
g_file = fopen("/dev/null", "w");
setbuffer(g_file, buffer, sizeof buffer);
bench("/dev/null");
fclose(g_file);
g_file = fopen("/tmp/log", "w");
setbuffer(g_file, buffer, sizeof buffer);
bench("/tmp/log");
fclose(g_file);
g_file = NULL;
g_logFile.reset(new muduo::LogFile("test_log_st", 500*1000*1000, false));//非线程安全,不加锁
bench("test_log_st");
g_logFile.reset(new muduo::LogFile("test_log_mt", 500*1000*1000, true));//线程安全方式写入
bench("test_log_mt");
g_logFile.reset();
}
输出