#include #include #ifdef WIN32 #include #include #endif #include #include <_ast.h> #include <_memchk.h> #include #include #include #include #include #include #include "ShareUtil.h" #include #include "DataPacket.hpp" #include "FileLogger.h" #include #include 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; isetPosition(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> 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 m_WriteMsgList; //待写入到文件的消息列表 CLockList m_FreeMsgList; //空闲消息包列表 CBaseList 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(); }