#include "Nave.h" #include "NFLog.h" #include "NFLogManager.h" #include "NFThreadManager.h" namespace Nave { NFLogThread::NFLogThread() : m_pLogHandle(NULL), m_bCompress(TRUE), m_hFlush(CreateEvent(0, TRUE, FALSE, 0)), m_hFile(INVALID_HANDLE_VALUE), m_dwTotalWritten(0), m_dwMaxFileSize(MAX_FILE_SIZE) { InterlockedExchange(&m_bEnd, FALSE); } NFLogThread::~NFLogThread() { if(INVALID_HANDLE_VALUE != m_hFile) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; } if(0 != m_hFlush) { CloseHandle(m_hFlush); m_hFlush = 0; } } VOID NFLogThread::Initialize(NFLogManager* pLog, BOOL bCompress) { m_bCompress = bCompress; m_pLogHandle = pLog; } unsigned int NFLogThread::Run() { // ¿©±â¼­ m_bEnd°¡ TRUE°¡ ¾Æ´Ï¸é ½º·¹µå°¡ ÀÛµ¿Çϰí ÀÖ´Ù. for(;TRUE != InterlockedCompareExchange(&m_bEnd, TRUE, TRUE);) { // ÇöÀç À̺¥Æ®°¡ »ç¿ëÁßÀ̸é 1Ãʰ£ ´ë±âÈÄ ´Ù½Ã È®ÀÎ. if(WAIT_TIMEOUT == WaitForSingleObject(m_hFlush, 1000)) { continue; } WriteLog(); }; WriteLog(); return 0; } BOOL NFLogThread::End() { InterlockedExchange(&m_bEnd, TRUE); SetEvent(m_hFlush); return TRUE; } BOOL NFLogThread::WriteLog() { // ·Î±×¿¡¼­ ¹öÆÛ¸¦ Àоî¿Â´Ù. if(!m_pLogHandle) return FALSE; m_pLogHandle->SpliceInWriteBuffer(m_WriteBufferList); if(m_WriteBufferList.empty()) return TRUE; if(INVALID_HANDLE_VALUE == m_hFile) { SetLogFileName(); m_hFile = CreateFileW(m_szLogFileName, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if(INVALID_HANDLE_VALUE == m_hFile) { return FALSE; } } unsigned long dwWritten = 0; for(NFLogBuffer::List::iterator itr = m_WriteBufferList.begin(); itr != m_WriteBufferList.end(); ++itr) { NFLogBuffer* pLogBuffer = *itr; if(FALSE == WriteFile(m_hFile, pLogBuffer->m_Buffer, pLogBuffer->m_dwUsage, &dwWritten, 0)) { LOG_ERROR((L"·Î±× ÆÄÀÏ ±â·Ï¿¡ ½ÇÆÐÇß½À´Ï´Ù. ErrorNum : %d, FileHandle:0x%p, ¹öÆÛ Å©±â:%d", GetLastError(), m_hFile, pLogBuffer->m_dwUsage)); } m_dwTotalWritten += dwWritten; } m_pLogHandle->SpliceInFreeBuffer(m_WriteBufferList); // ÆÄÀÏÀº °è¼Ó ¿­¾î³õ´Â´Ù. if(m_dwTotalWritten > m_dwMaxFileSize) { if(INVALID_HANDLE_VALUE != m_hFile) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; } // ÆÄÀÏ ´Ý°í... m_dwTotalWritten = 0; } return TRUE; } BOOL NFLogThread::SetLogFileName() { SYSTEMTIME sysTime; GetLocalTime(&sysTime); unsigned long dwSpinCount = 0; WCHAR szProgramName[MAX_PATH]; WCHAR szLogFilePrefix[MAX_PATH]; // ÇÁ·Î±×·¥À̸§°ú µ¿ÀÏÇÑ ÇÏÀ§Æú´õ¸¦ »ý¼ºÇÑ´Ù. Nave::GetProgramName(szProgramName, MAX_PATH); if(m_pLogHandle) _snwprintf(szLogFilePrefix, MAX_PATH - 1, L"%s", m_pLogHandle->GetLogFilePrefix()); else wcsncpy(szLogFilePrefix, szProgramName, MAX_PATH); if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(szProgramName)) { if (!CreateDirectoryW(szProgramName, 0)) { return FALSE; } } while (TRUE) { int LogLen = _snwprintf(m_szLogFileName, MAX_PATH, L"%s\\%s-%04d%02d%02d-%02d%02d%02d-%04d.log", szProgramName, szLogFilePrefix, sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond, dwSpinCount); if(LogLen <= 0) { LOG_ERROR((L"»ó¼¼ ·Î±×¸¦ À§ÇÑ ÆÄÀÏ À̸§À» »ý¼ºÇÒ ¼ö ¾ø½À´Ï´Ù.")); return FALSE; } if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(m_szLogFileName)) { break; } ++dwSpinCount; } return TRUE; } NFLogManager::NFLogManager(void) : m_lpDetailBuffer(0) { } NFLogManager::~NFLogManager(void) { Destroy(); } BOOL NFLogManager::Initialize(BOOL bCompress, const WCHAR* szLogFilePrefix) { WCHAR strName[MAX_PATH]; Nave::GetProgramName(strName, MAX_PATH); wcsncpy(m_szLogFilePrefix, strName, MAX_PATH); if(szLogFilePrefix != 0) { wcscat(m_szLogFilePrefix, szLogFilePrefix); } // óÀ½¿¡ ÇÁ¸®¹öÆÛ °³¼ö¸¸Å­ ¸¸µç´Ù. for(int nCount = 0; nCount < DEFAULT_FREE_LOG_BUFFER_NUM; ++nCount) { NFLogBuffer* pDetailBuffer = new NFLogBuffer; if(0 == pDetailBuffer) { LOG_ERROR((L"»ó¼¼ ·Î±× ¹öÆÛ¸¦ ÇÒ´çÇÏ´Â µ¥ ½ÇÆÐÇß½À´Ï´Ù")); Destroy(); return FALSE; } m_FreeList.push_back(pDetailBuffer); }; // ¹öÆÛ°¡ ¾øÀ¸´Ï ¿ì¼± 1°³ °¡Á®¿È. if(m_lpDetailBuffer == 0) { m_lpDetailBuffer = GetBuffer(); } m_LogSaveThread.Initialize(this, bCompress); if(INVALID_HANDLE_VALUE == NFThreadManager::Run(&m_LogSaveThread)) { LOG_ERROR((L"Flush½º·¹µå¸¦ »ý¼ºÇÏ´Â µ¥ ½ÇÆÐÇß½À´Ï´Ù")); return FALSE; } return TRUE; } BOOL NFLogManager::Destroy() { Flush(); NFThreadManager::Stop(&m_LogSaveThread, INFINITE); // ½ÌÅ©°Ç´Ù. NFSyncLock CL(&m_LogSync); NFLogBuffer* pDetailBuffer; for(NFLogBuffer::List::iterator itr = m_FreeList.begin(); itr != m_FreeList.end(); ++itr) { pDetailBuffer = (*itr); _DELETE(pDetailBuffer); } m_FreeList.clear(); for(NFLogBuffer::List::iterator itr = m_WriteList.begin(); itr != m_WriteList.end(); ++itr) { pDetailBuffer = (*itr); _DELETE(pDetailBuffer); } m_WriteList.clear(); return TRUE; } VOID NFLogManager::SetLogMaxSize(DWORD dwSize) { m_LogSaveThread.SetLogMaxSize(dwSize); } NFLogBuffer* NFLogManager::GetBuffer() { // ½ÌÅ©°Ç´Ù. NFSyncLock CL(&m_LogSync); NFLogBuffer* pLogBuffer = 0; if(m_FreeList.empty()) { // ³²´Â ¹öÆÛ°¡ ¾øÀ¸¸é ½Ç½Ã°£À¸·Î »ý¼ºÇعö¸°´Ù. ¾î¿¼ö¾ø´Ù. pLogBuffer = new NFLogBuffer; } else { pLogBuffer = m_FreeList.front(); m_FreeList.pop_front(); } if(0 == pLogBuffer) { LOG_ERROR((L"»ó¼¼ ·Î±× ¹öÆÛ¸¦ ÇÒ´çÇÒ ¼ö ¾ø½À´Ï´Ù.")); return 0; } pLogBuffer->Initialize(); return pLogBuffer; }; BOOL NFLogManager::Flush() { // ¹öÆÛ¸¦ ³Ö´Â´Ù. PushBuffer(&m_lpDetailBuffer); return m_LogSaveThread.FlushSignal(); } char* NFLogManager::ReserveBuffer(unsigned short usReserve) { NFSyncLock CL(&m_LogSync); if(0 == m_lpDetailBuffer) { m_lpDetailBuffer = GetBuffer(); } if(NFLogBuffer::MAX_LOG_BUFFER < m_lpDetailBuffer->m_dwUsage + usReserve) { Flush(); // ¹öÆÛ°¡ ²ËáÀ¸´Ï ÀúÀåÇØ¶ó. m_lpDetailBuffer = GetBuffer(); } if(0 == m_lpDetailBuffer) { LOG_ERROR((L"·Î±× ¹öÆÛ°¡ 0ÀÔ´Ï´Ù.")); return 0; } // ÄÄÇø®Æ®¸¦ ¸ÕÀúÇØ¼­ ÇØ´ç¿µ¿ªÀ» È®º¸ÇÑ´Ù. char* pPoint = &m_lpDetailBuffer->m_Buffer[m_lpDetailBuffer->m_dwUsage]; Complete(usReserve); return pPoint; } VOID NFLogManager::SpliceInWriteBuffer(NFLogBuffer::List& logBufferList) { NFSyncLock CL(&m_LogSync); if(m_WriteList.empty()) return; // WriteBuffer ¸¦ °¡Á®¿Â´Ù. logBufferList.splice(logBufferList.end(), m_WriteList); } VOID NFLogManager::SpliceInFreeBuffer(NFLogBuffer::List& logBufferList) { NFSyncLock CL(&m_LogSync); if(logBufferList.empty()) return; m_FreeList.splice(m_FreeList.end(), logBufferList); } VOID NFLogManager::PushBuffer(NFLogBuffer** ppDetailBuffer) { if(0 == *ppDetailBuffer) { return; } NFSyncLock CL(&m_LogSync); if(0 == (*ppDetailBuffer)->m_dwUsage) { // »çÀÌÁî°¡ 0ÀÌ´Ï ´Ù½Ã Free¿¡ ³ÖÀ½. m_FreeList.push_back(*ppDetailBuffer); } else { m_WriteList.push_back(*ppDetailBuffer); } // À̺κР´ë¹®¿¡ ÀÌÁ߯÷ÀÎÅÍ·Î º¯¼ö¸¦ ¹ÞÀº°Í. *ppDetailBuffer = 0; } }