異步日誌文件模塊實現
前先時間,在公司做的一個項目,當時並沒有覺得有什麼問題;但是後來發現,在寫日誌的時候,每次都是同步在寫,尤其是寫文件,這個是比較耗時的,所以就想優化一下;
優化方案:
-
異步讀寫
這裏的異步是利用隊列來做
每個模塊都將日誌寫入隊列,不關心寫入成功還是失敗;創建線程專門用於讀取隊列中的日誌信息,進行寫日誌文件
-
情景圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tRTy7K6R-1582939007578)(D:\學習總結\網絡通信\異步日誌文件\1.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;
}
總結:
這就是一個簡單的異步日誌實現,項目流程比較簡單,這個也可以符合要求;其實現在存在大量的消息隊列的開源庫,性能比較高,不過自己去設計、排錯也是一個成長的過程;
想了解學習更多C++後臺服務器方面的知識,請關注:
微信公衆號:CPP後臺服務器開發
");
return 0;
}
**************
********
**總結:**
這就是一個簡單的異步日誌實現,項目流程比較簡單,這個也可以符合要求;其實現在存在大量的消息隊列的開源庫,性能比較高,不過自己去設計、排錯也是一個成長的過程;
************
想了解學習更多C++後臺服務器方面的知識,請關注:
微信公衆號:====**CPP後臺服務器開發**====
**************