C++ 自定义简单的异步日志类
C++ 自定义简单的异步日志类
背景:在项目中由于将写日志功能放到了主线程中,导致主线程执行某个功能时会造成界面的卡顿。在调试程序过程中,发现是频繁的同步写日志操作导致界面卡顿。在把同步写日志函数注释后,函数执行不再卡顿,功能也正常。但是该功能没有写入日志信息了。这样操作就不能更好的排查问题了。所以就采用异步写日志的方法。
自定义异步日志类:
.h文件
#pragma once
#include<afx.h>
#include<afxmt.h>
#include<afxwin.h>
#include<windows.h>
#include<deque>
#include<string>
#include<fstream>
using namespace std;
class CAsyncLog
{
public:static CAsyncLog& Instance();void Log(const CString& strLog);void Stop();private:CAsyncLog();~CAsyncLog();static UINT WriteLogThread(LPVOID lpvoid);void SwapBuffers();void WriteToFile(deque<string>& buffer);bool m_bRuning;CWinThread* m_pThread;// 前端缓冲区deque<string> m_frontBuffer;// 后端缓冲区deque<string> m_backBuffer;// 临界区,实现线程同步CCriticalSection m_cs;// 输出文件ofstream m_file;
};
.cpp文件
#include <time.h>
CAsyncLog& CAsyncLog::Instance()
{static CAsyncLog m_asyncLog;return m_asyncLog;
}CAsyncLog::CAsyncLog()
{TCHAR szPath[MAX_PATH];::GetModuleFileName(NULL,szPath,MAX_PATH);CString strFile(szPath);strFile = strFile.Left(strFile.ReverseFind('\\')+ 1);strFile += _T("app.log");m_bRuning = true;m_file.open(strFile.GetBuffer(),ios::app);strFile.ReleaseBuffer();m_pThread = AfxBeginThread(WriteLogThread,this);
}CAsyncLog::~CAsyncLog()
{Stop();
}UINT CAsyncLog::WriteLogThread(LPVOID lpvoid)
{CAsyncLog* pAsyncLog = (CAsyncLog*)lpvoid;while (pAsyncLog->m_bRuning){// 每100ms查询一次::Sleep(100);pAsyncLog->SwapBuffers();}// 线程退出前写入剩余的日志信息pAsyncLog->SwapBuffers();return 0;
}void CAsyncLog::Log(const CString& strText)
{CSingleLock lock(&m_cs,TRUE);CTime tm = CTime::GetCurrentTime();CString strTime = tm.Format(_T("[%Y-%m-%d %H:%M:%S] "));// 转换为streamCStringA strBuffer(strTime + strText);string strLog = static_cast<const char*>(strBuffer);m_frontBuffer.push_back(strLog);
}void CAsyncLog::Stop()
{m_bRuning = false;if (m_pThread){::WaitForSingleObject(m_pThread->m_hThread,5000);m_pThread = nullptr;}if (m_file.is_open()){m_file.close();}
}void CAsyncLog::WriteToFile(deque<string>& buffer)
{deque<string>::const_iterator it = buffer.begin();for (;it != buffer.end();it++){m_file << *it << "\r\n";}m_file.flush();
}void CAsyncLog::SwapBuffers()
{CSingleLock lock(&m_cs,TRUE);if (m_frontBuffer.empty())return;m_frontBuffer.swap(m_backBuffer);WriteToFile(m_backBuffer);m_backBuffer.clear();
}
该类的使用方式是:
#include <iostream>
#include"AsyncLog.h"int main()
{for (int i=0;i<10;i++){CString str;str.Format(_T("AsyncLog Test,%d"),i);CAsyncLog::Instance().Log(str);}std::cout << "Hello World!\n";
}
说明:日志生成再当前软件的运行目录下。