서버같은 서비스 프로그램을 구현하다 보면,
어쩔 수 없이 로그에 많은 부분을 의지하게 된다.
파일이나 패킷을 통한 디버깅에도 한계가 있고,
그러다 보니 Windows의 시스템 로그를 많이 사용하게 된다.
Windows 시스템 로그란?
<시작-관리도구-이벤트 뷰어>
위와 같은 형태로 윈도우 시스템으로 저장하는 로그를 말한다.
우선, 서비스에 대한 소스를 등록하고,
HANDLE RegisterEventSource( _In_ LPCTSTR lpUNCServerName, _In_ LPCTSTR lpSourceName );
< 출처 : MSDN - RegisterEventSource Function (Windows) >
여기에 로그를 쌓는 API 함수는 다음과 같다.
BOOL ReportEvent( _In_ HANDLE hEventLog, _In_ WORD wType, _In_ WORD wCategory, _In_ DWORD dwEventID, _In_ PSID lpUserSid, _In_ WORD wNumStrings, _In_ DWORD dwDataSize, _In_ LPCTSTR *lpStrings, _In_ LPVOID lpRawData );
< 출처: MSDN - Report Event Function (Windows) >
위 함수를 사용하여 무작정 이벤트를 저장 할 경우, 한가지 문제가 생긴다.
Test Program 원본에서 이벤트 ID 0에 대한 설명을 찾을 수 없습니다. 이 이벤트를 발생시킨 구성 요소가 로컬 컴퓨터에 설치되어 있지 않거나 설치가 손상되었습니다. 로컬 컴퓨터에서 구성 요소를 설치 또는 복구할 수 있습니다.
이벤트가 다른 컴퓨터에서 시작된 경우 표시 정보를 이벤트와 함께 저장해야 합니다.
다음 정보가 이벤트와 함께 포함되었습니다.
이벤트 문자열
메시지 리소스가 있지만 문자열/메시지 테이블에서 메시지를 찾을 수 없습니다
바로 위와같이 이상한 오류같은 문자가 포함된다는 것 !!!
이런 현상이 발생하는 이유는 위의 RegisterEventSource 에서 사용된 이벤트 명이 이벤트 소스로 제대로 등록되어 있지
않기 때문에 발생한다.
그런 고로, 다음과 같은 순서로 이벤트로그 저장 루틴을 구현하면 깔끔하게 해결 할 수 있다.
1. 이벤트 메시지 파일 생성
- Message File을 다음과 같은 포멧으로 생성한다. (확장자 mc인 파일이며, ANSI로 저장하여도 상관 없다)
2. 이벤트 메시지 파일을 mc.exe (Message Compiler) 를 이용하여 컴파일
- 원래 기본적으로는 Windows SDK에 포함되어 있다고 하던데, 내 경우에는, Windows Kits 안에 있었다..
- 컴파일 방법은 뭐.. 간단하게 mc 메시지파일.mc 로 수행한다. (난 VS2008에서 빌드이벤트로 안되서 커맨드로 수행 하였다)
- 컴파일이 되면 다음과 같은 파일이 생성된다.
메시지파일.rc
메시지파일.h
메시지파일_KOR.bin, 메시지파일_ENG.bin 등, 메시지 파일에 정의 된 언어의 갯수에 따라 생성 됨
3. 컴파일 된 리소스 파일 등록
- 일단 VS 2008 기준으로, 기본 리소스 파일 (없을 시 기본으로 하나 생성하면 됨)의 리소스내용 에서 컴파일 타임 지시문
항목에 추가 해준다.
#include "메지시파일.rc"
4. 메시지 소스를 레지스트리에 등록
- 메시지가 이제 실행파일에 포함되었으므로, 이벤트표시기에 정보를 등록하여야 한다.
이때, 레지스트리를 이용한다.
● 레지스트리 경로 : HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\이벤트소스명
HKEY hKey = NULL; CString szKey; szKey.Format(_T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s"),m_szServiceName); // 레지스트리 생성 if (::RegCreateKey(HKEY_LOCAL_MACHINE, LPCTSTR(szKey), &hKey) != ERROR_SUCCESS) { ::CloseServiceHandle(hService); ::CloseServiceHandle(hSCM); return FALSE; } // Add the Event ID message-file name to the 'EventMessageFile' subkey. ::RegSetValueEx(hKey,_T("EventMessageFile"),0,REG_EXPAND_SZ, (CONST BYTE*)szFilePath,_countof(szFilePath)); // Set the supported types flags. DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; ::RegSetValueEx(hKey, _T("TypesSupported"), 0, REG_DWORD, (CONST BYTE*)&dwData, sizeof(DWORD)); ::RegCloseKey(hKey);
<예시>
5. 로그를 사용할 소스에서는 당연히, 메시지파일.h를 include 하여 사용하여야 한다.
위 단계에 따라 수행하게 되면, 깔끔(?)한 윈도우 이벤트 로그가 쌓이게 될 것이다.
내가 직접 구현하면서 당면했던 몇가지 상황에 대해서 추가로 정리를 해보자면,
case 1. mc.exe 컴파일러 파일 어딨지??
- 조사에 의하면 windows sdk에 포함되었다고 하지만, 어느샌가 그게 빠졌다고 한다.
찾아보니 Program Files의 Windows Kit 폴더 안에 있어서 그걸 사용했다.
case 2. 파일을 찾을 수 없다는 컴파일 에러 발생
- rc 파일응 컴파일 하고 위치에 대한 bin 파일등에 대해서 다시 한번 점검 필요.
'Develope > MFC' 카테고리의 다른 글
[CTreeCtrl] 트리 컨트롤 Drag & Drop (0) | 2013.03.18 |
---|---|
Overlapped IO 와 IOCP 이야기 (4) (0) | 2013.03.13 |
Overlapped IO 와 IOCP 이야기 (3-2) (0) | 2013.03.13 |
Overlapped IO 와 IOCP 이야기 (3-1) (0) | 2013.03.13 |
Overlapped IO 와 IOCP 이야기 (2) (0) | 2013.03.13 |
Overlapped IO 와 IOCP 이야기 (1) (1) | 2013.03.13 |
Visual Leak Detector (Memory Leak 찾기) (0) | 2013.02.14 |
MINI DUMP 파일이 0KB 인 경우? (0) | 2013.01.24 |
다이얼로그 트레이 동작 설정 (1) | 2013.01.14 |
컨트롤 폰트 설정 (0) | 2012.12.18 |