文章目录
日志写入逻辑
调用fwrite与write的吞吐量是不一样的,fwrite的ops比write的大
我们可以看到,fwrite与write的区别,当单次发送的数据的大小会影响效率
Log4cpp日志框架
日志级别
日志格式化
日志输出
日志回滚
比如说我们可以只保存最近的一个日志,最大文件大小,超过多少数进行回滚,还有追加一个文件
配置文件
Log4cpp范例讲解
配置文件剖析
message其实就是warn_log.info(“Program info which cannot be wirten, darren = %d”, 100);这里边打引号的内容
Category就是warn_log.setAdditivity(false);
Appender
output,这里每个appender只有一个输入模式
layout的设置,patternlayout可以去设置输出格式
log4cpp::PatternLayout* pLayout2 = new log4cpp::PatternLayout();
pLayout2->setConversionPattern("%d: %p %c %x: %m%n");
这两句可以设置layout的格式
// 1 读取解析配置文件
// 读取出错, 完全可以忽略,可以定义一个缺省策略或者使用系统缺省策略
// BasicLayout输出所有优先级日志到ConsoleAppender
try {
log4cpp::PropertyConfigurator::configure("./3-test_log4cpp.conf");//加载配置文件
} catch(log4cpp::ConfigureFailure& f) {
std::cout << "Configure Problem " << f.what() << std::endl;
return -1;
}
// 2 实例化category对象
// 这些对象即使配置文件没有定义也可以使用,不过其属性继承其父category
// 通常使用引用可能不太方便,可以使用指针,以后做指针使用
// log4cpp::Category* root = &log4cpp::Category::getRoot();
log4cpp::Category& root = log4cpp::Category::getRoot();//树状
log4cpp::NDC::push(__FUNCTION__); // 记录NDC信息
// log4cpp::NDC::push("ndc2");
log4cpp::Category& sub1 =
log4cpp::Category::getInstance(std::string("sub1"));
log4cpp::Category& sub1 =
log4cpp::Category::getInstance(std::string("sub1"));
log4cpp::Category& sub1_sub2 =
log4cpp::Category::getInstance(std::string("sub1.sub2"));
// 3 正常使用这些category对象进行日志处理。
// sub1 has appender A1 and rootappender.
sub1.info("sub1 This is some info");
# 文件名: 3-test_log4cpp.conf
# a simple test config
#定义了3个category sub1, sub2, sub1.sub2
# category 有两个参数 日志级别,Appender
log4cpp.rootCategory=DEBUG, rootAppender
# log4cpp.category.sub1设置日志级别默认和root一致, Appender为A1
log4cpp.category.sub1=,A1
# log4cpp.category.sub2设置为INFO,Appender默认使用root的
log4cpp.category.sub2=INFO
#log4cpp.category.sub1.sub2=ERROR, A2
log4cpp.category.sub1.sub2=, A2
# 设置sub1.sub2 的additivity属性,该属性默认值为true
# 如果值为true,则该Category的Appender包含了父Category的Appender, 即是日志也从root的appender输出
# 如果值为false,则该Category的Appender取代了父Category的Appender
log4cpp.additivity.sub1=false
# sub1.sub2的日志也从sub1的appender输出
log4cpp.additivity.sub1.sub2=true
#定义rootAppender类型和layout属性
log4cpp.appender.rootAppender=org.apache.log4cpp.ConsoleAppender
log4cpp.appender.rootAppender.layout=org.apache.log4cpp.BasicLayout
#定义A1的属性
log4cpp.appender.A1=org.apache.log4cpp.FileAppender
log4cpp.appender.A1.fileName=A1.log
log4cpp.appender.A1.layout=org.apache.log4cpp.SimpleLayout
#定义A2的属性
log4cpp.appender.A2=org.apache.log4cpp.ConsoleAppender
log4cpp.appender.A2.layout=org.apache.log4cpp.PatternLayout
#log4cpp.appender.A2.layout.ConversionPattern=The message '%m' at time
# log4cpp.appender.A2.layout.ConversionPattern=%d %m %n
# %d 时间戳 %t 线程名 %x NDC %p 优先级 %m log message 内容 %n 回车换行
log4cpp.appender.A2.layout.ConversionPattern=%d %p %x - %m%n
多层次
运行代码,我们看的出来性能区别还是挺大的
客户端那个RollingFileAppend,要检查文件大小,这样性能会比较差
Log4cpp调用栈分析
性能测试
日志回滚
已经有五个日志文件了,先删除最老的那个log5,然后再把其他的日志文件的文件名字的数字加一,然后新建日志
实时写入磁盘单笔write
多行100累积再写入->累积了99行,另一方一直不来,这要单独起一个定时器(例如1秒)去刷新,同一个日志管理线程去刷新数据
日志回滚每次都读取日志文件大小,肯定不能每次读取文件大小
muduo日志库分析
异步日志机制
怎么唤醒日志罗盘线程读取日志写入磁盘
每次发notify对性能有没有影响,mutex多线程互斥
不要发notify,累积多行日志再发送
缓存多条日志才能唤醒日志罗盘线程
日志写入磁盘时是批量写入
双缓冲机制
1、日志notify问题
写满一个buffer才一次notify插入日志 —日志api调用的线程
通过wait_timeout去读取日志,然后写入磁盘 — 日志罗盘线程
如果是超时唤醒,如果buffera此时只有1M数据,这边肯定是要读走的,然后写入磁盘
2、能够避免buffer不断分配
3、buffer默认4M一个
buffers是buffer队列,push,pop时使用mov语义减少内存拷贝
效率与延迟是成反比的