#include "stdafx.h" #include "Logger.h" Logger* Logger::m_pLogger = NULL; CRITICAL_SECTION Logger::s_cs; int Logger::bInitialized = 0; tstring Logger::m_strLogDirOrFilePath = DEFAULT_LOG_NAME; FileModeEnum Logger::m_eFileMode = Default_Mode; Logger::CAutoWriteHelper Logger::helper; Logger::Logger(void) :m_bWriteRealTime(true), m_fileName(DEFAULT_LOG_NAME), //Change it for SpBranch m_usWriteStatus(LEVEL_INFOR_WRITEABLE), m_bufCurLen(0), hMutexForBuffer(NULL), hEventWrite(NULL) { QueryPerformanceFrequency(&m_liPerfFreq); m_strBuffer = TLOG_TEXT(""); SetFileWriteMode(Day_Seperated_Mode); hMutexForBuffer = CreateMutex(NULL, FALSE, LPCTSTR("iGobalBuffer")); if(!m_bWriteRealTime) { hEventWrite = CreateEvent(NULL, TRUE, FALSE, TLOG_TEXT("iGobalTimerWriteEvent")); } } Logger::~Logger(void) { WaitForSingleObject(hMutexForBuffer, INFINITE); if(m_strBuffer.length() > 0) { bool retFlag = false; if(m_eFileMode == Day_Seperated_Mode) { m_fileName = GetCustomTime(For_File_Type); } retFlag = WriteToFile(m_strBuffer); if(retFlag) { m_strBuffer = TLOG_TEXT(""); m_bufCurLen = 0; } } ReleaseMutex(hMutexForBuffer); if(hMutexForBuffer && hMutexForBuffer != INVALID_HANDLE_VALUE) { CloseHandle(hMutexForBuffer); hMutexForBuffer = NULL; } if(hEventWrite && hEventWrite != INVALID_HANDLE_VALUE) { CloseHandle(hEventWrite); hEventWrite = NULL; } DeleteCriticalSection(&s_cs); bInitialized = 0; } tstring Logger::GetCustomTime(DateTypeEnum type) { tchar strTime[MAX_TIME_LEN] = {0}; time_t now; time(&now); tm *pTm = new tm; localtime_s(pTm, &now); if(type == For_File_Type) { _tcsftime(strTime, MAX_TIME_LEN*sizeof(tchar), TLOG_TEXT("%Y%m%d.log"), pTm); return (m_strLogDirOrFilePath + TLOG_TEXT("\\") + strTime); } else if(type == For_Record_Type) { _tcsftime(strTime, MAX_TIME_LEN*sizeof(tchar), TLOG_TEXT("[%Y/%m/%d %H:%M:%S] "), pTm); return tstring(strTime); } return TLOG_TEXT(""); } tstring Logger::GetTimeOfDay() { FILETIME time; double timed; tchar strTime[MAX_TIME_LEN] = {0}; GetSystemTimeAsFileTime( &time ); // Apparently Win32 has units of 1e-7 sec (tenths of microsecs) // 4294967296 is 2^32, to shift high word over // 11644473600 is the number of seconds between // the Win32 epoch 1601-Jan-01 and the Unix epoch 1970-Jan-01 // Tests found floating point to be 10x faster than 64bit int math. timed = ((time.dwHighDateTime * 4294967296e-7) - 11644473600.0) + (time.dwLowDateTime * 1e-7); tm *pTm = new tm; long temp = (long) timed; time_t clock = (long) timed; long appendix = (long) ((timed - temp) * 1e6); localtime_s(pTm, &clock); if(m_eFileMode == Day_Seperated_Mode) { _tcsftime(strTime, MAX_TIME_LEN, TLOG_TEXT("[%H:%M:%S"), pTm); } else { _tcsftime(strTime, MAX_TIME_LEN, TLOG_TEXT("[%Y/%m/%d %H:%M:%S"), pTm); } int nowLen = strlen(strTime); sprintf_s(strTime+nowLen, MAX_TIME_LEN-nowLen, TLOG_TEXT(",%03d] "), appendix / 1000); // //int appendix2 = appendix % 1000; //sprintf_s(strTime+nowLen, MAX_TIME_LEN-nowLen, ",%03d.%03d] ", appendix / 1000, appendix2); return tstring(strTime); } void Logger::Trace(tstring strInfo) { bool retFlag = false; WaitForSingleObject(hMutexForBuffer, INFINITE); m_strBuffer += strInfo; m_strBuffer += TLOG_TEXT("\r\n"); //Compatable for RVC framework //m_strBuffer += strInfo; if(m_bWriteRealTime || m_strBuffer.length() > MAX_INFOR_LEN) { if(m_eFileMode == Day_Seperated_Mode) { m_fileName = GetCustomTime(For_File_Type); } //MessageBox(NULL, TLOG_TEXT(m_fileName.c_str()), // TLOG_TEXT(""), MB_ICONINFORMATION | MB_OK); retFlag = WriteToFile(m_strBuffer); if(retFlag) { m_strBuffer = TLOG_TEXT(""); m_bufCurLen = 0; } } ReleaseMutex(hMutexForBuffer); } Logger* Logger::GetInstance() { EnterCriticalSection(&s_cs); if(m_pLogger == NULL) { m_pLogger = new Logger(); //if(m_pLogger) //{ // unsigned int threadID = 0; // HANDLE threadHD = (HANDLE)_beginthreadex(NULL, 0, Logger::TimerWriteProc, m_pLogger, 0, &threadID); // if(threadHD && threadHD != INVALID_HANDLE_VALUE) // { // CloseHandle(threadHD); // } //} } LeaveCriticalSection(&s_cs); return m_pLogger; } void Logger::InitLog(FileModeEnum eMode, const tchar* lpszDir) { if(bInitialized == 0) { InitializeCriticalSection(&s_cs); SetFileWriteMode(eMode, lpszDir); bInitialized = 1; } } void Logger::TraceInfor(const tchar* strInfo) { if((m_usWriteStatus & LEVEL_INFOR_WRITEABLE) != LEVEL_INFOR_WRITEABLE) return; tstring str(GetTimeOfDay()+TRACE_INFOR); str += strInfo; Trace(str); } void Logger::TraceDebug(const tchar* strInfo) { if((m_usWriteStatus & LEVEL_DEBUG_WRITEABLE) != LEVEL_DEBUG_WRITEABLE) return; tstring str(GetTimeOfDay()+TRACE_DEBUG); str += strInfo; Trace(str); } void Logger::TraceWarning(const tchar* strInfo) { if((m_usWriteStatus & LEVEL_WARNING_WRITEABLE) != LEVEL_WARNING_WRITEABLE) return; tstring str(GetTimeOfDay() + TRACE_WARNNING); str += strInfo; Trace(str); } void Logger::TraceError(const tchar* strInfo) { if((m_usWriteStatus & LEVEL_ERROR_WRITEABLE) != LEVEL_ERROR_WRITEABLE) return; tstring str(GetTimeOfDay() + TRACE_ERROR); str += strInfo; Trace(str); } void Logger::TraceDefault(const tchar* strInfo) { if((m_usWriteStatus & LEVEL_TRACE_WRITEABLE) != LEVEL_TRACE_WRITEABLE) return; tstring str(GetTimeOfDay() + TRACE_DEFAULT); str += strInfo; Trace(str); } void Logger::Trace_format(const tchar* fmt, va_list list_arg) { //_vstprintf_s int n; #ifdef UNICODE n = _vscwprintf(fmt, list_arg); #else n = _vscprintf(fmt, list_arg); #endif if(n > 0) { tchar *buf = new tchar[n+1]; memset(buf, 0, sizeof(tchar)*(n+1)); #ifdef UNICODE vswprintf_s(buf, n+1, fmt, list_arg); #else vsprintf_s(buf, n+1, fmt, list_arg); #endif Trace(tstring(buf)); delete buf; buf = NULL; } va_end(list_arg); } void Logger::TraceInfor_f(const tchar* fmt, ...) { if((m_usWriteStatus & LEVEL_INFOR_WRITEABLE) != LEVEL_INFOR_WRITEABLE) return; tstring str(GetTimeOfDay()+TRACE_INFOR + fmt); va_list arg; va_start(arg, fmt); Trace_format(str.c_str(), arg); } void Logger::TraceDebug_f(const tchar* fmt, ...) { if((m_usWriteStatus & LEVEL_DEBUG_WRITEABLE) != LEVEL_DEBUG_WRITEABLE) return; tstring str(GetTimeOfDay()+TRACE_DEBUG + fmt); va_list arg; va_start(arg, fmt); Trace_format(str.c_str(), arg); } void Logger::TraceWarning_f(const tchar* fmt, ...) { if((m_usWriteStatus & LEVEL_WARNING_WRITEABLE) != LEVEL_WARNING_WRITEABLE) return; tstring str(GetTimeOfDay()+TRACE_WARNNING + fmt); va_list arg; va_start(arg, fmt); Trace_format(str.c_str(), arg); } void Logger::TraceError_f(const tchar* fmt, ...) { if((m_usWriteStatus & LEVEL_ERROR_WRITEABLE) != LEVEL_ERROR_WRITEABLE) return; tstring str(GetTimeOfDay()+TRACE_ERROR + fmt); va_list arg; va_start(arg, fmt); Trace_format(str.c_str(), arg); } void Logger::TraceDefault_f(const tchar* fmt, ...) { if((m_usWriteStatus & LEVEL_TRACE_WRITEABLE) != LEVEL_TRACE_WRITEABLE) return; tstring str(GetTimeOfDay()+TRACE_DEFAULT + fmt); va_list arg; va_start(arg, fmt); Trace_format(str.c_str(), arg); } /*获取当前调用该日志文件的程序路径或程序名称(无类型后缀),主用于日志名称声明 *@param: [out] outFilePath 获取到程序路径或程序名称的字符串 * [in] sizeLen outFilePath字符数组的大小 * [in] fetchKind FALSE表示仅获取程序路径,TRUE表示获取程序名称 *@return 如果获取成功则表示实际得到的字符串长度,-1表示失败 */ DWORD Logger::GetCurExeNameOrPath(tchar* outFilePath, int sizeLen, int fetchKind) { DWORD tmpDwRes = 0; if(sizeLen <= 0) return -1; memset(outFilePath, 0, sizeof(tchar)*sizeLen); if(tmpDwRes = GetModuleFileName(NULL, outFilePath, sizeLen) == 0) { _stprintf_s(outFilePath, sizeLen, TLOG_TEXT("GetModuleFileName failed %d"), GetLastError()); return -1; } if(fetchKind == MODE_DEFAULT) { return tmpDwRes; } if(fetchKind == MODE_FILENAME_WITH_PATH) { tchar* pch2 = _tcsrchr(outFilePath, TLOG_TEXT('.')); if(pch2 == NULL) { return -1; } pch2[0] = TLOG_TEXT('\0'); return (int)(pch2 - outFilePath); } tchar* pch1 = _tcsrchr(outFilePath, TLOG_TEXT('\\')); if(fetchKind == MODE_DIRECTORY) { if(pch1 == NULL) { return -1; } if(int(pch1 - outFilePath) + 1 < sizeLen) { *(pch1 + 1) = TLOG_TEXT('\0'); } return (int)(pch1 - outFilePath + 1); } tchar tmpFilePath[MAX_PATH] = {0}; int idx = 0; tchar* pstart = pch1 + 1; if(fetchKind == MODE_FILENAME) { for(; *pstart != TLOG_TEXT('\0'); idx++) { tmpFilePath[idx] = *pstart++; } tmpFilePath[idx] = TLOG_TEXT('\0'); memcpy_s(outFilePath, sizeof(tchar)*sizeLen, tmpFilePath, sizeof(tchar)*(idx+1)); return idx+1; } if(fetchKind == MODE_FILENAME_ONLY) { tchar* pch2 = _tcsrchr(outFilePath, TLOG_TEXT('.')); if(pch1 == NULL || pch2 == NULL) { return -1; } for(; pstart < pch2; idx++) { tmpFilePath[idx] = *pstart++; } tmpFilePath[idx] = TLOG_TEXT('\0'); memcpy_s(outFilePath, sizeof(tchar)*sizeLen, tmpFilePath, sizeof(tchar)*(idx+1)); return idx+1; } return -1; } void Logger::DelayLoop(unsigned long usec) { LOG_FUNCTION(); LARGE_INTEGER freq, start, now; //返回硬件支持的高精度计数器的每秒钟嘀嗒的次数,零表示硬件不支持,读取失败 if (!QueryPerformanceFrequency(&freq)) { Sleep(usec); } else { QueryPerformanceCounter(&start); for(;;) { QueryPerformanceCounter((LARGE_INTEGER*) &now); if( ((double)(now.QuadPart - start.QuadPart) / (double)freq.QuadPart) * 1000 > usec ) break; } } } bool Logger::WriteToFile(tstring str) { bool flag = false; EnterCriticalSection(&s_cs); try { m_logStream.open(m_fileName.c_str(), tfstream::in | tfstream::app); if(!m_logStream) { //MessageBox(NULL, TLOG_TEXT(m_fileName.c_str()), // TLOG_TEXT(""), MB_ICONINFORMATION | MB_OK); str.clear(); } else if(m_logStream.is_open()) { m_logStream << str.c_str();// << endl; m_logStream.close(); flag = true; } } catch (std::exception e) { str.clear(); LeaveCriticalSection(&s_cs); return flag; } LeaveCriticalSection(&s_cs); return flag; } bool Logger::ClearToFile() { bool flag = false; WaitForSingleObject(hMutexForBuffer, INFINITE); if(m_strBuffer.length() > 0) { if(m_eFileMode == Day_Seperated_Mode) { m_fileName = GetCustomTime(For_File_Type); } flag = WriteToFile(m_strBuffer); if(flag) { m_strBuffer = TLOG_TEXT(""); m_bufCurLen = 0; } } ReleaseMutex(hMutexForBuffer); return flag; } void Logger::EndLog() { if(m_pLogger != NULL) { delete m_pLogger; m_pLogger = NULL; } } int Logger::FormatLastError(tchar* szOutMsg, unsigned int sizeLen, DWORD erroCode) { if(sizeLen == 0 || szOutMsg == NULL) return 0; LPVOID lpMsgBuf; if(erroCode == 0) { erroCode = GetLastError(); } if(!FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, erroCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL )) { return 0; } _tcscpy_s(szOutMsg, sizeLen,(LPCTSTR)lpMsgBuf); LocalFree(lpMsgBuf); return _tcslen(szOutMsg); } void Logger::Start() { QueryPerformanceCounter(&m_liPerfStart); } __int64 Logger::Now() const { LARGE_INTEGER liPerfNow; QueryPerformanceCounter(&liPerfNow); return (((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000) / m_liPerfFreq.QuadPart); } __int64 Logger::NowInMicro() const { LARGE_INTEGER liPerfNow; QueryPerformanceCounter(&liPerfNow); return (((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000000) / m_liPerfFreq.QuadPart); } void Logger::TraceErrWithLastCode(const tchar* strInfo) { DWORD dwErrCode = GetLastError(); TCHAR szMsg[MIN_INFOR_LEN] = {0}; int nLen = FormatLastError(szMsg, MIN_INFOR_LEN, dwErrCode); TraceError_f(TLOG_TEXT("%s : (%d)%s."), strInfo, dwErrCode, szMsg); return; } void Logger::SetFileWriteMode(FileModeEnum eMode, const tchar* lpszDir) { tchar fileName[MAX_PATH] = {0}; if(eMode == Single_File_Mode) { if(lpszDir == NULL || strlen(lpszDir) <= 0) { if(GetCurExeNameOrPath(fileName, MAX_PATH, MODE_FILENAME_WITH_PATH) != -1) { _tcscat_s(fileName, MAX_PATH*sizeof(tchar), TLOG_TEXT("_log.txt")); m_strLogDirOrFilePath = fileName; m_eFileMode = Single_File_Mode; if(m_pLogger != NULL && m_pLogger->RefleshFileName()){;} return; } } else { if(GetCurExeNameOrPath(fileName, MAX_PATH, MODE_FILENAME_ONLY) != -1) { _tcscat_s(fileName, MAX_PATH*sizeof(tchar), TLOG_TEXT("_log.txt")); m_strLogDirOrFilePath = lpszDir; const tchar* pchSuffix = _tcsrchr(lpszDir, TLOG_TEXT('\\')); if(pchSuffix == NULL || pchSuffix[1] != '\0') { m_strLogDirOrFilePath += tstring("\\"); } m_strLogDirOrFilePath += fileName; m_eFileMode = Single_File_Mode; if(m_pLogger != NULL && m_pLogger->RefleshFileName()){;} return; } } } else if(eMode == Day_Seperated_Mode) { if(strlen(lpszDir) <= 0) { if(GetCurExeNameOrPath(fileName, MAX_PATH, MODE_DIRECTORY) == -1) return; m_strLogDirOrFilePath = tstring(fileName) + TLOG_TEXT("LogFiles"); } else { const tchar* pchSuffix = _tcsrchr(lpszDir, TLOG_TEXT('\\')); if(pchSuffix != NULL && pchSuffix[1] == '\0') { _tcscpy_s(fileName, MAX_PATH*sizeof(tchar), lpszDir); fileName[strlen(fileName)-1] = TLOG_TEXT('\0'); m_strLogDirOrFilePath = tstring(fileName); } else { m_strLogDirOrFilePath = lpszDir; } //MessageBox(NULL, TLOG_TEXT(m_strLogDirOrFilePath.c_str()), // TLOG_TEXT(""), MB_ICONINFORMATION | MB_OK); } #ifndef UNICODE if(_access(m_strLogDirOrFilePath.c_str(), 0) == -1) #else char tlsDirectory[MAX_PATH] = {0}; int nt = WideCharToMultiByte(CP_ACP, 0, m_strLogDirOrFilePath.c_str(), -1, tlsDirectory, MAX_PATH, NULL, NULL); if(_access(tlsDirectory, 0) == -1) #endif { CreateDirectory(m_strLogDirOrFilePath.c_str(), NULL); } m_eFileMode = Day_Seperated_Mode; } else if(eMode == Default_Mode) { m_eFileMode = Default_Mode; m_strLogDirOrFilePath = DEFAULT_LOG_NAME; if(m_pLogger != NULL && m_pLogger->RefleshFileName()){;} } } const tchar * _GetFileNameForLog(const tchar *pszFilePath) { if(pszFilePath == NULL || _tcslen(pszFilePath) == 0) return TLOG_TEXT("empty"); const tchar* backlash = _tcsrchr(pszFilePath, (int)(TLOG_TEXT('\\'))); if(!backlash) { return pszFilePath; } return (backlash+1); } unsigned int _stdcall Logger::CAutoWriteHelper::TimerWriteProc(void* param) { if(param == nullptr) { return -1; } Logger::CAutoWriteHelper* helper = (Logger::CAutoWriteHelper*)param; HANDLE hEvent = helper->GetLogTimerEvent(); BOOL bLoop = TRUE; if(!hEvent) { return 0; } while(bLoop) { DWORD dwRet = WaitForSingleObject(hEvent, TIME_TO_WRITE_LOG); switch(dwRet) { case WAIT_OBJECT_0: //WRITE_TRACE_PARAM(TLOG_TEXT("WAIT_OBJECT_0")); helper->WriteToLog(); bLoop = FALSE; break; case WAIT_TIMEOUT: //WRITE_TRACE_PARAM(TLOG_TEXT("WAIT_TIMEOUT")); helper->WriteToLog(); break; case WAIT_FAILED: WRITE_TRACE_PARAM(TLOG_TEXT("WAIT_FAILED")); bLoop = FALSE; break; } } //WRITE_TRACE_PARAM(TLOG_TEXT("hiahiahia")); return 0; }