c++ 高性能日志库(muduo_AsyncLogging)

实现一个高效的网络日志库要解决那些问题?

首先明确一下问题的模型,这是一个典型的多生产者 单消费者问题,对于前端的日志库使用者来说,应该做到非阻塞添加,作为后端的文件写入,应该注意磁盘IO的瓶颈。

功能需求

  1. 日志的级别分级
  2. 发生时间和具体线程信息
  3. 线程安全

实现思路

多个线程共有一个前端,通过后端写入磁盘文件

异步日志是必须的,所以需要一个缓冲区,在这里我们使用的是多缓冲技术,基本思路是准备多块Buffer,前端负责向Buffer中填数据,后端负责将Buffer中数据取出来写入文件,这种实现的好处在于在新建日志消息的时候不必等待磁盘IO操作,前端写的时候也不会阻塞。

实现结构

LogStream 负责写入消息的格式化

LogFile 负责文件写入

AsyncLogging 负责实现 多缓冲技术 协调前后端

LogFile

如果有必要就给日至文件加锁

void LogFile::append(const char* logline, int len)
{
if (mutex_)
{
MutexLockGuard lock(*mutex_);
append_unlocked(logline, len);
}
else
{
append_unlocked(logline, len);
}
}

LogStream

重写流操作符

构造一个格式转化类,给日志中消息提供一个统一的格式

AsyncLogging

是及实现采用了四个缓冲区,这样可以进一步减少前端等待,数据结构

typedef boost::ptr_vector<LargeBuffer> BufferVector;
typedef BufferVector::auto_type BufferPtr;
MutexLock lock;
Condition cond;
BufferPtr nextBuffer;
BufferVector buffers_;

append的具体实现

在当前的缓冲区和备用缓冲区中选择一个足够使用的进行写入。

void AsynLogging::append(const char* logline, int len){
LockGuard(mutex);
if(curbuf->avail() > len){//当前缓冲区足够
curbuf->append(logline,len);
}
else{
buffers.push_back(curbuf->release());
if(nextbuf){
curbuf = std::move(nextbuf);
}
else{
curbuf.reset(new LargeBuffer);
}
curbuf->append(logline, len);
cond.notify();
}
}
  • 接收方的后端实现

    首先准备好两块空闲的buffer,已备在临界区内交换,等待条件标量出发的条件又两个,超时或者是前端写满了一个或者多个Buffer,当条件满足时,先将当前缓冲移入buffer,并且立刻将空闲的newBuffer1作为当前缓冲,接下来将buffers和buffersToWrite交换,随后将buffersToWrite写入文件,重新设计设置Buffer。
void AsyncLogging::threadFunc(){
BufferPtr nweBuffer1(new LargeBuffer);
BufferPtr newBuffer2(new LargeBuffer);
BufferVector bufferToWrite;
while(running_){
{
MutexLockGuard lock(mutex);
if(buffers.empty()){
cond.wait_for(muted,flushInterval_);
}
buffers.push_back(currentBuffer_.release());
currentBuffer = move(newBuffer1);
buffersTowrite.swap(buffers_);
if(!nextBuf){
nextBuf = std::move(newBuffer2);
}
}
}
}

交给后端去写入,以及重新设置两个缓冲区

	   for (size_t i = 0; i < buffersToWrite.size(); ++i)
{
// FIXME: use unbuffered stdio FILE ? or use ::writev ?
output.append(buffersToWrite[i].data(), buffersToWrite[i].length());
} if (buffersToWrite.size() > 2)
{
// drop non-bzero-ed buffers, avoid trashing
buffersToWrite.resize(2);
} if (!newBuffer1)
{
assert(!buffersToWrite.empty());
newBuffer1 = buffersToWrite.pop_back();
newBuffer1->reset();
} if (!newBuffer2)
{
assert(!buffersToWrite.empty());
newBuffer2 = buffersToWrite.pop_back();
newBuffer2->reset();
} buffersToWrite.clear();
output.flush();

c++ 高性能日志库(muduo_AsyncLogging)的更多相关文章

  1. 超轻量级、高性能C日志库--EasyLogger

    [ 声明:版权全部,欢迎转载.请勿用于商业用途. 联系信箱:armink.ztl@gmail.com] EasyLogger 1. 介绍 EasyLogger 是一款超轻量级(ROM<1.6K, ...

  2. 【腾讯Bugly干货分享】微信mars 的高性能日志模块 xlog

    本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/581c2c46bef1702a2db3ae53 Dev Club 是一个交流移动 ...

  3. 使用SeasLog打造PHP项目中的高性能日志组件(一)

    云智慧(北京)科技有限公司 高驰涛 什么是SeasLog SeasLog是一个C语言编写的PHP扩展,提供一组规范标准的功能函数,在PHP项目中方便.规范.高效地写日志,以及快速地读取和查询日志. 为 ...

  4. C/C++log日志库比较

    事实上,在C的世界里面没有特别好的日志函数库(就像Java里面的的log4j,或者C++的log4cxx).C程序员都喜欢用自己的轮子.printf就是个挺好的轮子,但没办法通过配置改变日志的格式或者 ...

  5. Logan:美团点评的开源移动端基础日志库

    前言 Logan是美团点评集团移动端基础日志组件,这个名称是Log和An的组合,代表个体日志服务.同时Logan也是“金刚狼”大叔的名号,当然我们更希望这个产品能像金刚狼大叔一样犀利. Logan已经 ...

  6. golang开发:类库篇(一) Zap高性能日志类库的使用

    为什么要用zap来写日志 原来是写PHP的,一直用的error_log,第一次写Go项目的时候,还真不知道该怎么写日志,后来就按照PHP的写法自己不成规范的捣鼓写.去了新公司之后,发现用的是zap.后 ...

  7. zap高性能日志

    摘要 日志在整个工程实践中的重要性不言而喻,在选择日志组件的时候也有多方面的考量.详细.正确和及时的反馈是必不可少的,但是整个性能表现是否也是必要考虑的点呢?在长期的实践中发现有的日志组件对于计算资源 ...

  8. 爆料喽!!!开源日志库Logger的剖析分析

    导读 Logger类提供了多种方法来处理日志活动.上一篇介绍了开源日志库Logger的使用,今天我主要来分析Logger实现的原理. 库的整体架构图 详细剖析 我们从使用的角度来对Logger库抽茧剥 ...

  9. 爆料喽!!!开源日志库Logger的使用秘籍

    日志对于开发来说是非常重要的,不管是调试数据查看.bug问题追踪定位.数据信息收集统计,日常工作运行维护等等,都大量的使用到.今天介绍著名开源日志库Logger的使用,库的地址:https://git ...

随机推荐

  1. Java Web 开发中路径相关问题小结

    Java Web开发中路径问题小结 (1) Web开发中路径的几个基本概念 假设在浏览器中访问了如下的页面,如图1所示: 图1 Eclipse中目录结构如图2所示: 图2 那么针对这个站点的几个基本概 ...

  2. Win2D 入门教程 VB 中文版 - 防止内存泄漏

    避免内存泄漏 本文从微软官方文档翻译 http://microsoft.github.io/Win2D/html/RefCycles.htm 如果文档有问题,可以在 https://github.co ...

  3. 原创:shell两个整数的比较 思想版

    思想是学的 代码创作是自己的 很喜欢前几行的逻辑严谨 #!/bin/bash#判断两个整数的大小read -p "请输入两个整数a b :" a b #或者使用a=$1[ -z & ...

  4. 【opencv】imread CV_LOAD_IMAGE_GRAYSCALE

    转灰度图的操作很多,但是opencv中的CV_LOAD_IMAGE_GRAYSCALE的具体操作为: gray = 0.299 * r + 0.587 * g + 0.114 * b 然后,小数点部分 ...

  5. DROP DATABASE - 删除一个数据库

    SYNOPSIS DROP DATABASE name DESCRIPTION 描述 DROP DATABASE 删除一个现存数据库的目录入口并且删除包含数据的目录. 只有数据库所有者能够执行这条命令 ...

  6. echart-柱状图

    目前在改别人遗留的bug,需求: 宽度 自适应的情况下 展示不友好:宽度太大 上下不居中 需求 要 上下 无论是否 有内容 都要居中展示 以0刻度为标准 宽度 设置 series: [ { name: ...

  7. JavaSE-26 Swing

    学习要点 关于Swing Swing容器组件 Swing布局管理器 Swing组件 Swing菜单组件 关于Swing Swing和AWT都是java开发图形用户界面的工具包. AWT:早期Java版 ...

  8. 《3+1团队》【Alpha】Scrum meeting 4

    项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 作业链接地址 团队名称 3+1团队 团队博客地址 https://home.cnblogs.com/u/3-1group ...

  9. More Effective C++ - 章节二 : 操作符(operators)

    5. 对定制的 "类型转换函数" 保持警觉 允许编译器执行隐式类型转换,害处多过好处,不要提供转换函数,除非你确定需要. class foo { foo(int a = 0, in ...

  10. <Spring Cloud>入门二 Eureka Client

    1.搭建一个通用工程 1.1 pom 文件 <?xml version="1.0" encoding="UTF-8"?> <project x ...