일을하면서 로그를 남겨야 할 일이 많아서 이와 같이구현한다.


#include <stdarg.h>

#include <stdio.h>


typedef enum {

NORMAL = 0,

WARNING = 1,

DEBUGMODE = 2,

} LogLevel; //로그레벨은 


class CLogWriter{

public:

CLogWriter(){  }

~CLogWriter(){  }


//method

public:

void InitializeLogWriter(){ //로그라이터 설정

GetWorkDirectory(strCurPath); //현재 디렉토리 가져오는 함수

    //로그 경로 만들기.

strLogPath.Format(_T("%s\\Log"), strCurPath);

if (::PathFileExists(strLogPath) == FALSE){

::CreateDirectory(strLogPath, NULL);

}

m_enCurLogLevel = (LogLevel)::GetPrivateProfileInt(_T("Logs"), _T("LogWriteLevel"), 0, strIniPath);


CTime curTime = CTime::GetTickCount();

//CONVLOG_YYYYMMDD_HH.log파일 형태로 파일명을 정하기 위함

m_strLogFilePath.Format(_T("%s\\CONVLOG_%04d%02d%02d_%02d.log"), strLogPath, 

               curTime.GetYear(), curTime.GetMonth(), curTime.GetDay(), curTime.GetHour());

  }


void WriteLog(LogLevel reqLogLevel, const TCHAR* strFormat, ...){

//요청된 로그 레벨이 현재 설정된 로그 레벨보다 낮으면 return

if (reqLogLevel > m_enCurLogLevel){ return; }

va_list Marker;

TCHAR szBuffer[1024];

memset(szBuffer, 0x00, sizeof(szBuffer));

va_start(Marker, strFormat);

    //어차피 로그를 남기려면 문자열로 남겨야 하니까. 귀찮아서 그냥 vsprintf로..

vsprintf_s(szBuffer,sizeof(szBuffer), strFormat, Marker);

va_end(Marker);

CString strLogFormat;

CTime curTime = CTime::GetTickCount();

strLogFormat.Format(_T("[%04d/%02d/%02d %02d:%02d:%02d] %s\r\n"), curTime.GetYear(), curTime.GetMonth(), curTime.GetDay(), curTime.GetHour(), curTime.GetMinute(), curTime.GetSecond(), szBuffer);

WriteLogToFile(strLogFormat);

}


private:

       //실제 파일에 기록하기

void WriteLogToFile(const CString& strLogString){

if (m_strLogFilePath.IsEmpty() == true){ InitializeLogWriter(); }

CFile file;

int flag = CFile::modeWrite;

//파일이 존재하지 않을 경우에만 modeCreate를 덧붙인다. 아닐경우 마지막 로그만 남음.

if (::PathFileExists(m_strLogFilePath) == FALSE){

flag = flag | CFile::modeCreate;

}

file.Open(m_strLogFilePath, flag);

file.SeekToEnd();    //파일 마지막에 덧붙이기 위함.

file.Write(strLogString, strLogString.GetLength() * sizeof(TCHAR)); //char의 크기를 정확하게 알수없으므로 무조건 TCHAR의 크기만큼 곱한다.

file.Close();

}


//variables

private:

LogLevel m_enCurLogLevel;

CString m_strLogFilePath;

};

저작자 표시 비영리 동일 조건 변경 허락
신고
by 곰돌이네 아바분대장 2016.10.13 14:15

참조 : https://msdn.microsoft.com/ko-kr/library/ms890887.aspx

역시 MS에서는 웬만한건 다 오픈해 준다. 남아있는 하드디스크 용량까지도.

 

바로... GetDiskFreeSpace (!!!)

함수 원형은

 GetDiskFreeSpaceA(
    LPCSTR lpRootPathName,
    LPDWORD lpSectorsPerCluster,
    LPDWORD lpBytesPerSector,
    LPDWORD lpNumberOfFreeClusters,
    LPDWORD lpTotalNumberOfClusters
  );

 lpRootPathName : 탐색할 드라이브 경로 (최상위 root)

 lpSectorsPerCluster : 클러스터당 섹터의 수

 lpBytesPerSector : 섹터당 바이트 크기

 lpNumberOfFreeClusters : 잔여용량 클러스터의 갯수

 lpTotalNumberOfClusters : 전체 클러스터 갯수

  -> 즉, 크기를 구할때 클러스터수 * lpSectorsPerCluster *  lpBytesPerSector 로 구할 수 있다.

 

 근데 위 함수는 읽어오는 용량 제한이 있다. 그래서.. Ex가 등장(!)했다. 함수 형태는 아래와 같다.

 

 BOOL GetDiskFreeSpaceEx(
    LPCWSTR lpDirectoryName,
    PULARGE_INTEGER lpFreeBytesAvailableToCaller,
    PULARGE_INTEGER lpTotalNumberOfBytes,
    PULARGE_INTEGER lpTotalNumberOfFreeBytes
);

 

 lpDirectoryName : 탐색할 드라이브의 최상위 root.

 lpFreeBytesAvailableToCaller : 호출한 스레드에서 사용가능한 최대의 용량. (사실상 free space)

 lpTotalNumberOfBytes : 드라이브의 총 용량

 lpTotalNumberOfFreeBytes : 드라이브의 잔여 용량.  NULL이 가능하다.

 

 ULARGE_INTEGER를 사용한다. 호출 예제는 아래와 같다.

 

 ULARGE_INTEGER uiFreeSpace, uiTotalSpace, uiTotalFreeByte;
uiFreeSpace.QuadPart = 0; uiTotalSpace.QuadPart = 0; uiTotalFreeByte.QuadPart = 0;
GetDiskFreeSpaceEx(_T("C:\\"), &uiFreeSpace, &uiTotalSpace, &uiTotalFreeByte);

 단위는 byte이므로 필요에 따라 단위 변환을 하면 된다.

 

 네트워크 드라이브도 찾아온다. 와우.

저작자 표시 비영리 동일 조건 변경 허락
신고
by 곰돌이네 아바분대장 2016.09.26 16:36

STL에서 즉.. new를 이용하여 생성한 객체를 삽입할 경우. 반드시 delete를 해줄것.

예를들어

 vector<MyStrcut> objStruct;

 for( int i = 0; i < iMax ; i++){

   MyStruct *pObj = new MyStruct;

   objStruct.push_back(pObj);

 }

...

 vector<MyStruct>::iterator itr;

 for(itr = objStruct.begin(); itr != objStruct.end(); itr++){

   SAFEDELETE(itr);

 }

 objStruct.clear();

 

 뭐.. 대략 위에처럼..

 cf. SAFEDELETE는 내가 주로 사용하는 delete관련 코드를 매크로로 만들어둔것.

 #define SAFEDELETE(X) if( X != NULL){ delete X; X = NULL; } 

 위 매크로를 사용하는것은 포인터 객체를 delete할때에는 언제나.. NULL체크를 해주어야 하므로..

define을 해두면 한줄로 끝나지만 안하면 몇줄을 타이핑 해야한다. 그게 귀찮아서.. -_-a 항상 헤더에 정의하고 사용중..

저작자 표시 비영리 동일 조건 변경 허락
신고
by 곰돌이네 아바분대장 2016.09.26 16:24