MFC 에서 멀티 쓰레드 또는 소켓 프로그램에서는 디버그 창이 약간 불편할 때가 있습니다. 실시간으로 확인해야 하는 상황이 있으니까요.
다중 쓰레드를 브레이크 포인트 걸면 정신 없습니다. 디버깅도 잘 되지 않고요. 이럴때는 로그를 남겨서 디버깅 하는게 좋습니다. 간단 Log Class 를 소개 해 드립니다.
만약 서버 프로그램을 개발 하신다면 Log를 남기는 것이 기본이라 여러 좋은 로깅 라이브러리를 이미 사용하고 계실테지만 UI 프로그램을 개발 하시는 분들은 디버그 윈도우 에서만 디버깅 하시는 분들이 많습니다.
이럴때 멀티스레드 디버깅을 위해 log4cxx, log4cpp 같은 라이브러리를 포팅 해서 쓰기에는 너무 무겁고 어렵습니다.
그래서 심플하게 로그를 남길 수 있는 간단 Log Class 를 블로깅 합니다. 이 클래스는 로그 기록 및 관리를 단순화하고, 디버그 프로세스를 효율적으로 만드는 데 도움이 됩니다.
사용법
포함된 로그 클래스를 그대로 붙여 넣기 하시고
InitInstance() 같은 초기화 함수에서 다음을 수행합니다.
CLog* pLog;
pLog = CLog::Instance();
pLog->CreateLog(_T("D:\\log.txt"), true); //로그 파일의 위치
그리고 사용하고자 하는 어떤곳에서든 다음처럼 로그를 남기면 됩니다.
CLog* pLog = CLog::Instance();
pLog->Log(_T("여기에 LOG 를 남기면 됩니다. "));
그리고 소멸자 또는 이제 사용이 끝났을 때는 다음처럼
CLog* pLog = CLog::Instance();
pLog->CloseLog();
CLog 는 SingleTone 으로 구현이 되어 있으므로 멤버 변수를 항상 갖고 있지 않고 CLog::Instance()로 포인터를 받아 옵니다.
한 함수에서 다음처럼 테스트를 한번 해보시고 사용 하시면 금방 익숙해 지실 것 같습니다.
CLog* pLog;
pLog = CLog::Instance();
pLog->CreateLog(_T("D:\\log.txt"), true); //로그 파일의 위치
pLog->Log(_T("로그를 남겨라"));
if (pLog)
pLog->CloseLog();
소스코드
소스 코드는 아래와 같습니다. CLog 클래스를 만드시고 아래 내용을 붙여 넣기 하시면 됩니다.
CLog.h
#pragma once
#include <memory>
using namespace std;
//*********************************************************************
// CLog
//*********************************************************************
class CLog
{
public:
// Functions
static CLog* Instance();
void CreateLog(CString sFilename, bool bEnableTimestamp);
void Log(CString sText);
void EnableTimestamp(bool bEnable = true);
void CloseLog();
private:
// Constructor & destructor
CLog(); // Private constructor because singleton!
// Functions
CString GetTime();
// Variables
static std::auto_ptr<CLog> sm_inst;
CStdioFile* m_pLogFile;
bool m_bEnableTimestamp;
};
CLog.cpp
#include "stdafx.h"
#include "CLog.h"
#include <conio.h>
std::auto_ptr<CLog> CLog::sm_inst;
//*********************************************************************
// CONSTRUCTOR & DESTRUCTOR
//*********************************************************************
CLog::CLog()
{
// Set file handler to NULL
m_pLogFile = NULL;
}
//*********************************************************************
// PUBLIC FUNCTIONS
//*********************************************************************
CLog* CLog::Instance()
{
if (sm_inst.get() == 0)
sm_inst = auto_ptr<CLog>(new CLog);
return sm_inst.get();
/* FOLLOWING CODE WORKS ONLY IN VC7
if(sm_inst.get() == 0)
sm_inst.reset(new CLog);
return sm_inst.get();
*/
}
//=====================================================================
void CLog::CreateLog(CString sFilename, bool bEnableTimestamp)
{
// Create the new log
m_pLogFile = new CStdioFile(
sFilename,
CFile::modeCreate | CFile::modeWrite |
CFile::shareDenyNone | CFile::typeBinary);
// Set timestamp option
m_bEnableTimestamp = bEnableTimestamp;
if (!AllocConsole())
AfxMessageBox(_T("Failed to create the console!"), MB_ICONEXCLAMATION);
// Write first part so the file is unicode
TCHAR bom = (TCHAR)0xFEFF;
m_pLogFile->Write(&bom, sizeof(TCHAR));
}
//=====================================================================
void CLog::Log(CString sText)
{
USES_CONVERSION;
// Check if log is already created
if (m_pLogFile == NULL)
return;
// Should we add time to beginning of string?
if (m_bEnableTimestamp)
{
sText.Insert(0, GetTime() + _T(" => "));
}
// Add \n\r to end of text
sText.Insert(sText.GetLength(), _T("\r\n"));
// Log text
m_pLogFile->Write(sText, sText.GetLength() * sizeof(TCHAR));
#ifdef _DEBUG
_cwprintf(_T("%s"), sText);
#endif
}
//=====================================================================
void CLog::CloseLog()
{
if (!FreeConsole())
AfxMessageBox(_T("Could not free the console!"));
// Close file
m_pLogFile->Close();
// Delete object
delete m_pLogFile;
// Set handle to NULL
m_pLogFile = NULL;
}
//=====================================================================
void CLog::EnableTimestamp(bool bEnable)
{
// Set timestamp option
m_bEnableTimestamp = bEnable;
}
//*********************************************************************
// PRIVATE FUNCTIONS
//*********************************************************************
CString CLog::GetTime()
{
// Declare variables
SYSTEMTIME time;
CString sTime;
// Get time
GetLocalTime(&time);
// Set up time
sTime.Format(
_T("%02d:%02d:%02d:%03d"),
time.wHour,
time.wMinute,
time.wSecond,
time.wMilliseconds);
// Return value
return sTime;
}
마무리
MFC 에서 멀티 쓰레드 같은 경우 디버깅이 쉽지 않습니다.
그때 간단하게 로그를 남기는 클래스를 소개해 드렸습니다.
MFC 에서 클레스를 만들고 위의 내용을 붙여 넣기 한 후 사용 하시면 됩니다.