[MFC] 간단 Log Class

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 에서 클레스를 만들고 위의 내용을 붙여 넣기 한 후 사용 하시면 됩니다.

Leave a Comment