阅读 13

异步日志文件模块实现

异步日志文件模块实现

Snipaste_2020-02-16_17-29-47.png

前先时间,在公司做的一个项目,当时并没有觉得有什么问题;但是后来发现,在写日志的时候,每次都是同步在写,尤其是写文件,这个是比较耗时的,所以就想优化一下;

优化方案:

  • 异步读写

    这里的异步是利用队列来做

    每个模块都将日志写入队列,不关心写入成功还是失败;创建线程专门用于读取队列中的日志信息,进行写日志文件

  • 情景图

使用队列的好处:

  • 解耦,这样每个模块独立,互补影响

  • 提高性能;每个模块都没有了写文件的损耗,所有写文件的损耗都由日志模块来承担;


实现

  • 这里实现是使用的队列使STL中的queue为底层,使用单例模式确保全局只有唯一的一个对象,保证使用相同的队列;

  • 使用开源库log4cplus作为读写日志库


注意:一般不同的模块就是一个线程,这时候就需要加锁,否则会出现访问权限冲突的问题;



这里写了一个简单的例子,仅供参考:

#pragma once
#include <iostream>
#include <queue>
#include <windows.h>
#include <mutex>

using namespace std;

struct MSGLOG
{
//0 info;1 error;
 int type;
 char info[256];
};

class QueueLog
{
public:
 QueueLog();
 static QueueLog& instance();
 ~QueueLog();
 bool SetLog(string logmsg,int type);
 MSGLOG GetLog();
private:
 MSGLOG msg;
 queue<MSGLOG>que;
 std::mutex _mutex;
};

#define LOG QueueLog::instance()
复制代码
#include "QueueLog.h"

QueueLog::QueueLog()
{

}

QueueLog::~QueueLog()
{

}

QueueLog& QueueLog::instance()
{
 static QueueLog quelog;
 return quelog;
}

bool QueueLog::SetLog(string logmsg, int type)
{
 std::lock_guard<mutex>lock(_mutex);
//不做判空
 memset(&msg,0,sizeof(msg));
 msg.type = type;
 memcpy(&msg.info, logmsg.c_str(), logmsg.length());
 que.push(msg);
 return true;
}

MSGLOG QueueLog::GetLog()
{
 std::lock_guard<mutex>lock(_mutex);
 MSGLOG getMsg;
 memset(&getMsg,0,sizeof(getMsg));
 if (que.empty())
 {
  goto EXIT;
 }
//while (que.empty())
//{
// Sleep(2);
//}
//Sleep(3);
 getMsg = que.front();
 que.pop();
EXIT:
 return getMsg;
}复制代码
#pragma once
#include <iostream>
#include <string>
#include <log4cplus/logger.h>
#include <log4cplus/configurator.h> 
#include <log4cplus/layout.h> 
#include <log4cplus/loggingmacros.h> 
#include <log4cplus/helpers/stringhelper.h> 

#define MY_LOG_FILE_PATH "../log/logconfig.properites"

using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;

class MyLogger
{
public:
 static MyLogger & getInstance();
 Logger logger;
private:
 MyLogger();
 ~MyLogger();
};

#define LOG4CPLUS MyLogger::getInstance()复制代码
#include "logger.h"

MyLogger::MyLogger()
{
 log4cplus::initialize();
 PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT(MY_LOG_FILE_PATH));
 logger = Logger::getRoot();

}


MyLogger & MyLogger::getInstance()
{
 static MyLogger log;
 return log;
}

MyLogger::~MyLogger()
{
}
复制代码
#include "QueueLog.h"
#include "test.h"
#include "logger.h"
#include <thread>

using namespace std;

void SetTest2()
{
 while (1)
 {
  MSGLOG msg;
  memset(&msg, 0, sizeof(msg));
  LOG.SetLog("test", 0);
  LOG.SetLog("test2", 0);
  LOG.SetLog("test3", 0);
  LOG.SetLog("test4", 0);
  Sleep(5);
 }

}

int main()
{
 std::thread t1(SetTest2);
 MSGLOG msg;
/*memset(&msg,0,sizeof(msg));
LOG.SetLog("test",0);*/
 SetTest();
 while (1)
 {
  memset(&msg, 0, sizeof(msg));
  msg = LOG.GetLog();
  switch(msg.type)
  {
   case 0:
    LOG4CPLUS_DEBUG(LOG4CPLUS.logger, msg.info);
    break;
   case 1:
    LOG4CPLUS_DEBUG(LOG4CPLUS.logger, msg.info);
    break;
  }
  cout << "id:" << msg.type << endl;
  cout << "msg:" << msg.info << endl;
//Sleep(1);
 }
 t1.join();
 system("pause");
 return 0;

复制代码


总结:

这就是一个简单的异步日志实现,项目流程比较简单,这个也可以符合要求;其实现在存在大量的消息队列的开源库,性能比较高,不过自己去设计、排错也是一个成长的过程;
END

想了解学习更多C++后台服务器方面的知识

请关注:微信公众号:====CPP后台服务器开发====

END
转载是一种动力 分享是一种美德





关注下面的标签,发现更多相似文章
评论