Files
mir_server/sdk/utils/FileLogger.cpp
aixianling 5c9f1dae4a init
2025-01-09 17:45:40 +08:00

461 lines
13 KiB
C++

#include <new>
#include <stdio.h>
#ifdef WIN32
#include <tchar.h>
#include <Windows.h>
#endif
#include <stdarg.h>
#include <_ast.h>
#include <_memchk.h>
#include <Tick.h>
#include <Lock.h>
#include <QueueList.h>
#include <Thread.h>
#include <Stream.h>
#include <RefClass.hpp>
#include "ShareUtil.h"
#include <BufferAllocator.h>
#include "DataPacket.hpp"
#include "FileLogger.h"
#include <time.h>
#include <FDOP.h>
using namespace wylib::sync::lock;
using namespace wylib::container;
using namespace wylib::stream;
class COPMToFile :
protected wylib::thread::CBaseThread
{
public:
COPMToFile(LPCTSTR lpLogFilePath):
wylib::thread::CBaseThread("COPMToFile")
{
char dirName[512];
FDOP::ExtractFileDirectory(lpLogFilePath,dirName,sizeof(dirName));
FDOP::DeepCreateDirectory(dirName);
m_fFile =new wylib::stream::CFileStream(lpLogFilePath,CFileStream::faWrite |
CFileStream::faShareRead , CFileStream::AlwaysCreate);
m_nRefer = 1;
m_WriteMsgList.setLock(&m_WriteMsgLock);
m_FreeMsgList.setLock(&m_FreeMsgLock);
//将写指针调整到文件末尾
m_fFile->seek(0, CFileStream::soEnd);
StartWorkThread();
m_bNeedDump = false;
#ifdef WIN32
m_hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
#endif
}
//增加引用计数,函数返回增加引用后的引用计数值
inline LONG addRef()
{
return InterlockedIncrement(&m_nRefer);
}
//减少引用计数,函数返回减少引用后的引用计数值
//当减少引用后引用计数为0则自动销毁对象自身。
inline LONG release()
{
LONG n = InterlockedDecrement(&m_nRefer);
if ( n == 0 )
delete this;
return n;
}
~COPMToFile()
{
INT_PTR i;
//终止数据写入线程
/*resume();
terminate();
waitFor();*/
StopWorkThread();
//销毁写入列表中的数据包
m_WriteMsgList.flush();
for (i=m_WriteMsgList.count()-1; i>-1; --i)
{
m_WriteMsgList[i]->~CDataPacket();
}
m_WriteMsgList.empty();
//销毁空闲列表中的数据包
for (i=m_FreeMsgList.count()-1; i>-1; --i)
{
m_FreeMsgList[i]->~CDataPacket();
}
m_FreeMsgList.empty();
//释放数据包内存
for (i=m_MsgPackMemList.count()-1; i>-1; --i)
{
m_Allocator.FreeBuffer(m_MsgPackMemList[i]);
}
m_MsgPackMemList.empty();
}
void addMsg(SHAREOUTPUTMSGTYPE eMsgType, LPCTSTR sText, INT_PTR nTextLen)
{
static const int PackBlockSize = 256;
CDataPacket *pPacket;
SYSTEMTIME sysTime;
m_FreeMsgList.lock();
INT_PTR nCount = m_FreeMsgList.count();
//如果空闲数据包队列没有数据了则申请PackBlockSize个数据包
if ( nCount <= 0 )
{
pPacket = (CDataPacket*)m_Allocator.AllocBuffer(sizeof(*pPacket) * PackBlockSize);
m_MsgPackMemList.add(pPacket);
for (int i=0; i<PackBlockSize; ++i )
{
new(pPacket)CDataPacket(&m_Allocator);
m_FreeMsgList.add(pPacket);
pPacket++;
}
nCount = PackBlockSize;
}
//从空闲数据包队列中取出最后一个
nCount--;
pPacket = m_FreeMsgList[nCount];
m_FreeMsgList.trunc(nCount);
m_FreeMsgList.unlock();
//清空数据
pPacket->setPosition(0);
//写入消息类型
*pPacket << eMsgType;
//写入时间
GetLocalTime(&sysTime);
pPacket->writeBuf(&sysTime, sizeof(sysTime));
//写入消息内容
*pPacket << (WORD)nTextLen;
pPacket->writeBuf(sText, nTextLen * sizeof(*sText));
*pPacket << (TCHAR)0;//写入终止符
//数据包追加到写数据列表中
m_WriteMsgList.append(pPacket);
}
void Dump()
{
m_bNeedDump = true;
}
protected:
VOID OnRountine()
{
while ( !terminated() )
{
if (m_bNeedDump)
{
DumpImpl();
m_bNeedDump = false;
}
ProcessMessages();
Sleep(16);
}
}
//处理所有日志记录
VOID ProcessMessages()
{
INT_PTR i, nCount;
SHAREOUTPUTMSGTYPE msgType;
size_t nMsgLen, nTmsLen;
LPCTSTR sMsg;
SYSTEMTIME sysTime;
TCHAR sTimeStr[64];
char sMsgBuf[4096];
m_WriteMsgList.flush();
nCount = m_WriteMsgList.count();
for (i=0; i<nCount; ++i)
{
CDataPacket &pack = *(m_WriteMsgList[i]);
pack.setPosition(0);
pack >> msgType;
pack >> sysTime;
#ifdef UNICODE
nMsgLen = pack.readWideString(NULL, 0);
#else
nMsgLen = pack.readString(NULL, 0);
#endif
pack >> sMsg;
if (sMsg)
{
nTmsLen = _stprintf( sTimeStr, _T("[%02d-%02d-%02d %02d:%02d:%02d]"), sysTime.wYear - 2000, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond );
//转换为ASC编码
#ifdef WIN32
convertToACP(sMsg, nMsgLen, sMsgBuf, ArrayCount(sMsgBuf));
//显示此消息
displayMessage(msgType, sTimeStr, sMsgBuf, nMsgLen);
//转换为UTF-8编码
nMsgLen = convertToUTF8(sMsg, nMsgLen, sMsgBuf, ArrayCount(sMsgBuf));
writeMessage(msgType, sTimeStr, nTmsLen, sMsgBuf, nMsgLen);
#else
displayMessage(msgType, sTimeStr, sMsg, nMsgLen);
writeMessage(msgType, sTimeStr, nTmsLen, sMsg, nMsgLen);
#endif
//向文件写入此消息
}
else if (IsDebuggerPresent())
{
DebugBreak();
}
}
//将写入列表的数据包全部还原回空闲列表中
m_FreeMsgList.lock();
m_FreeMsgList.addArray(m_WriteMsgList, nCount);
m_WriteMsgList.trunc(0);
m_FreeMsgList.unlock();
}
//向文件写入消息记录
void writeMessage(SHAREOUTPUTMSGTYPE msgType, const char* sTimeStr, const size_t nTmsLen, const char* sMsgBuf, const size_t nMsgLen)
{
static struct
{
LPCTSTR sBegin, sEnd;
size_t sizeBegin, sizeEnd;
}
FormatTags[] =
{
{ _T(""), _T("\n"), _tcslen(FormatTags[0].sBegin) * sizeof(FormatTags[0].sBegin[0]), _tcslen(FormatTags[0].sEnd) * sizeof(FormatTags[0].sEnd[0]), },
{ _T("[WRN]"), _T("\n"), _tcslen(FormatTags[1].sBegin) * sizeof(FormatTags[1].sBegin[0]), _tcslen(FormatTags[1].sEnd) * sizeof(FormatTags[1].sEnd[0]), },
{ _T("[TIP]"), _T("\n"), _tcslen(FormatTags[2].sBegin) * sizeof(FormatTags[2].sBegin[0]), _tcslen(FormatTags[2].sEnd) * sizeof(FormatTags[2].sEnd[0]), },
{ _T("[ERR]"), _T("\n"), _tcslen(FormatTags[3].sBegin) * sizeof(FormatTags[3].sBegin[0]), _tcslen(FormatTags[3].sEnd) * sizeof(FormatTags[3].sEnd[0]), },
};
m_fFile->write(sTimeStr, nTmsLen * sizeof(*sTimeStr));
if ( FormatTags[msgType].sizeBegin > 0 )
m_fFile->write(FormatTags[msgType].sBegin, FormatTags[msgType].sizeBegin);
m_fFile->write(sMsgBuf, nMsgLen * sizeof(*sMsgBuf));
if ( FormatTags[msgType].sizeEnd > 0 )
m_fFile->write(FormatTags[msgType].sEnd, FormatTags[msgType].sizeEnd);
}
//显示日志消息
void displayMessage(SHAREOUTPUTMSGTYPE msgType, const char* sTimeStr, const char* sMsgBuf, const size_t nMsgLen)
{
#ifdef WIN32
WORD wColorAttrs;
switch ( msgType )
{
case rmWaning:
wColorAttrs = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
break;
case rmError:
wColorAttrs = FOREGROUND_RED | FOREGROUND_INTENSITY;
break;
//case rmSystem:
// wColorAttrs = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
// break;
default:
wColorAttrs = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
break;
}
SetConsoleTextAttribute(m_hStdOut, wColorAttrs);
printf(sTimeStr);
switch ( msgType )
{
case rmWaning: printf( ("[WRN]") ); break;
case rmTip: printf( ("[TIP]") ); break;
case rmError: printf( ("[ERR]") ); break;
}
puts(sMsgBuf);
#else
switch ( msgType )
{
case rmWaning:
printf("\033[0;34m%s[WRN]%s\033[0m\r\n",sTimeStr,sMsgBuf);
break;
case rmError:
printf("\033[0;31m%s[ERR]%s\033[0m\r\n",sTimeStr,sMsgBuf);
break;
case rmTip:
printf("%s[TIP]%s\r\n",sTimeStr,sMsgBuf);
break;
default:
printf("%s%s\r\n",sTimeStr,sMsgBuf);
break;
}
#endif
}
#ifdef WIN32
//转换文字编码为UTF-8
size_t convertToUTF8(const char* lpMsg, const size_t nMsgLen, char *pBuffer, const size_t BufferLen)
{
WCHAR sWCBuf[4096];
DWORD cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, lpMsg, (int)nMsgLen, sWCBuf, ArrayCount(sWCBuf)-1);
if ( cch <= 0 )
cch = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, lpMsg, (int)nMsgLen, sWCBuf, ArrayCount(sWCBuf)-1);
if ( cch > 0 )
{
cch = (DWORD)WideCharToMultiByte(CP_UTF8, 0, sWCBuf, cch, pBuffer, (int)(BufferLen-1), NULL, NULL);
if ( cch > 0 )
{
pBuffer[cch] = 0;
return cch;
}
}
return 0;
}
//转换文字编码为ASC
size_t convertToACP(const char* lpMsg, const size_t nMsgLen, char *pBuffer, const size_t BufferLen)
{
WCHAR sWCBuf[4096];
DWORD cch = (DWORD)MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, lpMsg, (int)nMsgLen, sWCBuf, ArrayCount(sWCBuf)-1);
if ( cch > 0 )
{
cch = (DWORD)WideCharToMultiByte(CP_ACP, 0, sWCBuf, cch, pBuffer, int(BufferLen-1), NULL, NULL);
if ( cch > 0 )
{
pBuffer[cch] = 0;
return cch;
}
}
//本身就是ACP
else
{
cch = (DWORD)__min(BufferLen-1, nMsgLen);
memcpy(pBuffer, lpMsg, cch);
pBuffer[cch] = 0;
return cch;
}
return 0;
}
#endif
void DumpImpl()
{
using namespace wylib::stream;
using namespace wylib::container;
CFileStream fs(_T("FileLoggerStat.log"), CFileStream::faWrite, CFileStream::AlwaysOpen);
fs.setPosition(fs.getSize());
const TCHAR szSep[] = _T("-------------------------------------------------------------------------------------------\r\n");
time_t szClock;
time(&szClock);
struct tm curTime;
localtime_r(&szClock,&curTime);
TCHAR szDateTime[250] = {0};
_tcsftime(szDateTime, _tcslen(szDateTime)-1, _T("%Y-%m-%d %H:%M:%S\r\n"), &curTime);
fs.write(szSep, _tcslen(szSep)*sizeof(TCHAR));
fs.write(szDateTime, _tcslen(szDateTime)*sizeof(TCHAR));
TCHAR szDesc[256] = {0};
//_stprintf(szDesc, _T("%-40s%-25s%-25s%-25s%-25s\r\n"), _T("HandleMgrName"), _T("UsedHandleCount"), _T("MaxUsedHdlCount"), _T("AllocedBlockNum"), _T("HandlePerBlock"));
_stprintf(szDesc, _T("总分配的数据包数目 = %d\r\n"), m_MsgPackMemList.count());
fs.write(szDesc, _tcslen(szDesc)*sizeof(TCHAR));
CBufferAllocator::ALLOCATOR_MEMORY_INFO mi;
INT_PTR nFreeMsgCount = 0, nPrepareWriteMsgCount = 0;
// 获取空闲可用消息数量以及总共内存分配情况
m_FreeMsgList.lock();
nFreeMsgCount = m_FreeMsgList.count();
m_Allocator.GetMemoryInfo(&mi);
m_FreeMsgList.unlock();
_stprintf(szDesc, _T("小块内存总分配字节数 = %-20d, 空闲字节数=%d\r\n"), mi.SmallBuffer.dwAllocSize, mi.SmallBuffer.dwFreeSize);
fs.write(szDesc, _tcslen(szDesc)*sizeof(TCHAR));
_stprintf(szDesc, _T("中块内存总分配字节数 = %-20d, 空闲字节数=%d\r\n"), mi.MiddleBuffer.dwAllocSize, mi.MiddleBuffer.dwFreeSize);
fs.write(szDesc, _tcslen(szDesc)*sizeof(TCHAR));
_stprintf(szDesc, _T("大块内存总分配字节数 = %-20d, 空闲字节数=%d\r\n"), mi.LargeBuffer.dwAllocSize, mi.LargeBuffer.dwFreeSize);
fs.write(szDesc, _tcslen(szDesc)*sizeof(TCHAR));
_stprintf(szDesc, _T("超大块内存总分配字节数 = %-20d, 空闲字节数=%d\r\n"), mi.SuperBuffer.dwAllocSize, mi.SuperBuffer.dwFreeSize);
fs.write(szDesc, _tcslen(szDesc)*sizeof(TCHAR));
// 获取带写入的消息数量
m_WriteMsgList.lock();
nPrepareWriteMsgCount = m_WriteMsgList.count() + m_WriteMsgList.appendCount();
m_WriteMsgList.unlock();
_stprintf(szDesc, _T("空闲日志消息数量 = %-20d, 待写入消息数量=%d\r\n"), nFreeMsgCount, nPrepareWriteMsgCount);
fs.write(szDesc, _tcslen(szDesc)*sizeof(TCHAR));
fs.write(szSep, _tcslen(szSep)*sizeof(TCHAR));
}
private:
LONG m_nRefer; //引用计数
CBufferAllocator m_Allocator; //内存管理器
CCSLock m_WriteMsgLock; //待写入到文件的消息列表锁
CCSLock m_FreeMsgLock; //空闲消息包列表锁
CQueueList<CDataPacket*> m_WriteMsgList; //待写入到文件的消息列表
CLockList<CDataPacket*> m_FreeMsgList; //空闲消息包列表
CBaseList<CDataPacket*> m_MsgPackMemList;//消息包列表内存头指针列表
bool m_bNeedDump;
wylib::stream::CFileStream* m_fFile;
#ifdef WIN32
HANDLE m_hStdOut;
#endif
};
COPMToFile *g_pOPMToFile;
SHAREOUTPUTMSGFN lpOldFnBeforeSet;
INT_PTR STDCALL OutputMsgToFileFn(SHAREOUTPUTMSGTYPE MsgType, LPCTSTR lpMsg, INT_PTR nMsgLen)
{
g_pOPMToFile->addMsg(MsgType, lpMsg, nMsgLen);
return nMsgLen;
}
void DumpFileLogger()
{
g_pOPMToFile->Dump();
}
const TCHAR* getCurrentTimeDesc()
{
static TCHAR szDataTime[256] = {0};
//time_t szClock;
//time(&szClock);
//struct tm *curTime = localtime(&szClock);
//_tcsftime(szDataTime, sizeof(szDataTime)-1, _T("%Y-%m-%d %H-%M-%S"), curTime);
SystemTime sysTime;
GetSystemTime(sysTime);
SNPRINTFA(szDataTime, sizeof(szDataTime) - 1, "%s%d%d%d.txt", szDataTime, sysTime.year_, sysTime.mon_, sysTime.mday_);
return szDataTime;
}
CFileLogger::CFileLogger(LPCTSTR sLogFileNamePattern, ...)
{
if ( !g_pOPMToFile )
{
TCHAR* pszFileName = new TCHAR[MAX_PATH];
va_list ap;
va_start(ap, sLogFileNamePattern);
_vsntprintf(pszFileName, MAX_PATH-1, sLogFileNamePattern, ap);
va_end(ap);
g_pOPMToFile = new COPMToFile(pszFileName);
lpOldFnBeforeSet = SetOutputMsgFn(OutputMsgToFileFn);
delete []pszFileName;
}
else g_pOPMToFile->addRef();
}
CFileLogger::~CFileLogger()
{
if ( g_pOPMToFile )
{
if ( g_pOPMToFile->release() == 0 )
{
SetOutputMsgFn(lpOldFnBeforeSet);
g_pOPMToFile = NULL;
}
}
}
void CFileLogger::Dump()
{
if (g_pOPMToFile)
g_pOPMToFile->Dump();
}
void CFileLogger::DumpToFile()
{
if (g_pOPMToFile)
g_pOPMToFile->Dump();
}