引言
眾所周知,在調試、跟蹤和執行應用程序的過程中,程序的日志能為這些工作提供大量有價值的運行信息。因此,程序的日志對應用程序的運行、維護至關重要。
在如何記錄程序日志方面,通常有三種選擇:
1、采用Log4CXX等公共開源日志組件:這類日志組件的特點是跨平台且功能比較強大,例如可以把日志發往另一台服務器或記錄到數據庫中等;另外,可配置性較高,可以通過配置文件或程序代碼對日志進行很多個性化設置。但從另外一個角度看,由於這些優點往往也導致了在使用方面的缺點。首先,對於一般應用程序來說,它們並不需要太多的功能,通常只需要把日志記錄到文件或反饋到應用程序,功能太多反正讓用戶使用起來覺得繁瑣還得背負很多從來都用不到的代碼。其次,這類日志組件通常是跨平台的,並不只是針對 Windows 或 VC 的應用程序,因此使用起來總會覺得有點別扭,例如他們的字符都是用 char 類型的,對於一個 Unicode 程序來說每次寫日志都要做字符轉換是很不爽的事情,本座在多年前曾經使用過 Log4Cpp ,程序執行時總是報告日志組件有內存洩露,雖然有可能是誤報,但是使用起來總覺得很不舒服。
2、自己寫幾個簡單的類或函數記錄日志:這種方法的確很簡單,通常都不用一兩百行的代碼。但這種方法通常缺乏規范性和通用性,其他程序需要記錄類似的但有點差異的日志時,通常的作法是:Copy-Paste-Modify;另外,這類方法很可能也沒有考慮性能或並發方面的問題,通常是直接在工作線程中寫日志,對於那些性能要求較高的應用程序是絕對不允許的。
3、干脆不記錄任何日志:的確,現在很多程序由於各種原因並沒有記錄任何日志。但本座以為,如果一個程序是有用的,具備一定功能,並且需要連續運行較長一段時間,那麼記錄日志是必須的;否則,得認真考慮該程序是否有存在的必要了。
設計
綜上所述,編寫一個通用的日志組件應該著重考慮三個方面:功能、可用性和性能。下面,本座詳細說明在設計日志組件時對這些方面問題的考慮:
1、功能:本日志組件的目的是滿足大多數應用程序記錄日志的需求 —— 把日志輸出到文件或發送到應用程序中,並不提供一些復雜但不常用的功能。本日志組件的功能包括:
把日志信息輸出到指定文件
每日生成一個日志文件
對於 GUI 程序,可以把日志信息發送到指定窗口
對於Console應用程序,可以把日志信息發往標准輸出 (std::cout)
支持 MBCS / UNICODE,Console / GUI 程序
支持動態加載和靜態加載日志組件 DLL
支持 DEBUG/TRACE/INFO/WARN/ERROR/FATAL 等多個日志級別
2、可用性:本日志組件著重考慮了可用性,盡量讓使用者用起來覺得簡便、舒心:
簡單純淨:不依賴任何程序庫或框架
使用接口簡單,不需復雜的配置或設置工作
提供 CStaticLogger 和 CDynamicLogger 包裝類用於靜態或動態加載以及操作日志組件,用戶無需關注加載細節
程序如果要記錄多個日志文件只需為每個日志文件創建相應的 CStaticLogger 或 CDynamicLogger 對象
只需調用 Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法記錄日志
日志記錄方法支持可變參數
日志輸出格式:<時間> <線程ID> <日志級別> <日志內容>
3、性能:性能是組件是否值得使用的硬指標,本組件從設計到編碼的過程都盡量考慮到性能優化:
支持多線程同時發送寫日志請求
使用單獨線程在後台寫日志,不影響工作線程的正常執行
采用批處理方式批量記錄日志
接口
1、ILogger:日志組件對象接口
1 /******************************************************************************
2 Module: Logger.h
3 Notices: Copyright (c) 2012 Bruce Liang - www.2cto.com
4
5 Purpose: 記錄程序日志。
6 1. 把日志信息輸出到指定文件
7 2. 對於 GUI 程序,可以把日志信息發送到指定窗口
8 3. 對於Console應用程序,可以把日志信息發往標准輸出 (std::cout)
9
10 Desc:
11 1、功能:
12 --------------------------------------------------------------------------------------
13 a) 把日志信息輸出到指定文件
14 b) 每日生成一個日志文件
15 c) 對於 GUI 程序,可以把日志信息發送到指定窗口
16 d) 對於Console應用程序,可以把日志信息發往標准輸出 (std::cout)
17 e) 支持 MBCS / UNICODE,Console / GUI 程序
18 f) 支持動態加載和靜態加載日志組件 DLL
19 g) 支持 DEBUG/TRACE/INFO/WARN/ERROR/FATAL 等多個日志級別
20
21 2、可用性:
22 --------------------------------------------------------------------------------------
23 a) 簡單純淨:不依賴任何程序庫或框架
24 b) 使用接口簡單,不需復雜的配置或設置工作
25 c) 提供 CStaticLogger 和 CDynamicLogger 包裝類用於靜態或動態加載以及操作日志組件,用戶無需關注加載細節
26 d) 程序如果要記錄多個日志文件只需為每個日志文件創建相應的 CStaticLogger 或 CDynamicLogger 對象
27 e) 只需調用 Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法記錄日志
28 f) 日志記錄方法支持可變參數
29 g) 日志輸出格式:<時間> <線程ID> <日志級別> <日志內容>
30
31 3、性能:
32 --------------------------------------------------------------------------------------
33 a) 支持多線程同時發送寫日志請求
34 b) 使用單獨線程在後台寫日志,不影響工作線程的正常執行
35 c) 采用批處理方式批量記錄日志
36
37 Usage:
38 方法一:(靜態加載 Logger DLL)
39 --------------------------------------------------------------------------------------
40 0. 應用程序包含 StaticLogger.h 頭文件
41 1. 創建 CStaticLogger 對象(通常為全局對象)
42 2. 調用 CStaticLogger->Init(...) 初始化日志組件
43 3. 使用 CStaticLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
44 4. 調用 CStaticLogger->UnInit(...) 清理日志組件(CStaticLogger 對象析構時也會自動清理日志組件)
45
46 方法二:(動態加載 Logger DLL)
47 --------------------------------------------------------------------------------------
48 0. 應用程序包含 DynamicLogger.h 頭文件
49 1. 創建 CDynamicLogger 對象(通常為全局對象)
50 2. 調用 CDynamicLogger->Init(...) 初始化日志組件
51 3. 使用 CDynamicLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
52 4. 調用 CDynamicLogger->UnInit(...) 清理日志組件(CDynamicLogger 對象析構時也會自動清理日志組件)
53
54 方法三:(直接用導出函數加載 Logger DLL)
55 --------------------------------------------------------------------------------------
56 0. 應用程序包含 Logger.h 頭文件
57 1. 手工調用 ILoger_Create() 和 ILoger_Create() 導出函數創建和銷毀 ILogger 對象
58 (注:如果是動態加載,需手工調用 ::LoadLibrary()/::FreeLibrary() 系列 API 函數加載和卸載 Logger DLL)
59
60 [
61 ***** 對於希望通過窗口接收日志信息的 GUI 程序 *****
62
63 A. 日志組件初始化成功後調用 SetGUIWindow(HWND) 設置收日志的窗口
64 B. 窗口須響應處理 LOG_MESSAGE 消息
65 C. 處理完 LOG_MESSAGE 消息後,調用 ILogger::FreeLogMsg() 銷毀接收到的 TLogMsg
66 ]
67
68 Environment:
69 1. Windows 2000 or later (_WIN32_WINNT >= 0x0500)
70 2. VC++ 2010 or later
71
72 Release:
73 1. Logger_C.dll - Console/MBCS/Release
74 2. Logger_CD.dll - Console/MBCS/Debug
75 3. Logger_CU.dll - Console/Unicode/Release
76 4. Logger_CUD.dll - Console/Unicode/Debug
77 5. Logger.dll - GUI/MBCS/Release
78 6. Logger_D.dll - GUI/MBCS/Debug
79 7. Logger_U.dll - GUI/Unicode/Release
80 8. Logger_UD.dll - GUI/Unicode/Debug
81
82 Examples:
83 1. TestGUILogger - GUI 版測試程序 (靜態加載)
84 2. TestDynamicLogger - GUI 版測試程序 (動態加載)
85 3. TestConsoleLogger - Console 版測試程序 (靜態加載)
86
87 ******************************************************************************/
88
89 #pragma once
90
91 /**************************************************/
92 /********** imports / exports Logger.dll **********/
93
94 #ifdef LOGGER_EXPORTS
95 #define LOGGER_API __declspec(dllexport)
96 //#define TRY_INLINE inline
97 #else
98 #define LOGGER_API __declspec(dllimport)
99 //#define TRY_INLINE
100 #endif
101
102 /**************************************************/
103 /****************** 日志組件接口 *******************/
104
105 class LOGGER_API ILogger
106 {
107 public:
108 /***** 日志級別 *****/
109 enum LogLevel
110 {
111 LL_NONE = 0XFF,
112 LL_DEBUG = 1,
113 LL_TRACE = 2,
114 LL_INFO = 3,
115 LL_WARN = 4,
116 LL_ERROR = 5,
117 LL_FATAL = 6
118 };
119
120 /***** 操作錯誤碼 *****/
121 enum ErrorCode
122 {
123 // 無錯誤
124 EC_OK = NO_ERROR,
125 // 文件操作相關的錯誤
126 EC_FILE_GENERIC,
127 EC_FILE_FILENOTFOUND,
128 EC_FILE_BADPATH,
129 EC_FILE_TOMANYOPERFILES,
130 EC_FILE_ACCESSDENIED,
131 EC_FILE_INVALIDFILE,
132 EC_FILE_REMOVECURRENTDIR,
133 EC_FILE_DIRECTORYFULL,
134 EC_FILE_BADSEEK,
135 EC_FILE_HARDIO,
136 EC_FILE_SHARINGVIOLATION,
137 EC_FILE_LOCKVIOLATION,
138 EC_FILE_DISKFULL,
139 EC_FILE_ENDOFFILE,
140 // 其他錯誤
141 EC_INVALID_STATE,
142 EC_INIT_LOGLEVEL,
143 EC_INIT_PRINTFLAG,
144 EC_INIT_CREATE_LOG_THREAD_FAIL
145 };
146
147 /******************************************
148 日志信息結構
149 *******************************************/
150 struct TLogMsg
151 {
152 DWORD m_dwSize; // 結構大小 - 跟據消息長度動態變化
153 LogLevel m_logLevel; // 日志級別
154 UINT m_uiThreadID; // 線程ID
155 SYSTEMTIME m_stMsgTime; // 記錄時間
156 TCHAR m_psMsg[1]; // 消息內容
157 };
158
159 public:
160 ILogger(void);
161 virtual ~ILogger(void);
162 private:
163 ILogger(const ILogger&);
164 ILogger& operator = (const ILogger&);
165
166 public:
167 // 日志組件初始化方法
168 virtual BOOL Init(
169 LPCTSTR logFile = NULL // 日志文件. 默認: {AppPath}/logs/{AppName}-YYYYMMDD.log
170 , LogLevel ll = DEFAULT_LOG_LEVEL // 日志級別. 默認: [Debug -> LL_DEBUG] / [Release -> LL_INFO]
171 , int printFlag = DEFAULT_PRINT_FLAG // 輸出掩碼. 是否輸出到文件和(或)屏幕. 默認: 只輸出到文件
172 ) = 0;
173 // 日志組件清理方法
174 virtual BOOL UnInit() = 0;
175
176 public:
177 // 寫日志方法:傳入日志內容字符串(對於不需要格式化的日志文本,用本方法效率最高)
178 virtual void Log_0 (LogLevel ll, LPCTSTR msg) = 0;
179 virtual void Debug_0(LPCTSTR msg);
180 virtual void Trace_0(LPCTSTR msg);
181 virtual void Info_0 (LPCTSTR msg);
182 virtual void Warn_0 (LPCTSTR msg);
183 virtual void Error_0(LPCTSTR msg);
184 virtual void Fatal_0(LPCTSTR msg);
185
186 // 寫日志方法:傳入格式化字符串和參數棧指針(通常只在組件內部使用)
187 virtual void LogV (LogLevel ll, LPCTSTR format, va_list arg_ptr);
188
189 // 寫日志方法:傳入格式化字符串和可變參數(非常靈活簡便)
190 virtual void Log (LogLevel ll, LPCTSTR format, ...);
191 virtual void Debug (LPCTSTR format, ...);
192 virtual void Trace (LPCTSTR format, ...);
193 virtual void Info (LPCTSTR format, ...);
194 virtual void Warn (LPCTSTR format, ...);
195 virtual void Error (LPCTSTR format, ...);
196 virtual void Fatal (LPCTSTR format, ...);
197
198 // 寫日志方法:傳入格式化字符串和可變參數(與上一組方法類似,但在進行任何操作前會檢查日志級別)
199 virtual void TryLog (LogLevel ll, LPCTSTR format, ...);
200 virtual void TryDebug (LPCTSTR format, ...);
201 virtual void TryTrace (LPCTSTR format, ...);
202 virtual void TryInfo (LPCTSTR format, ...);
203 virtual void TryWarn (LPCTSTR format, ...);
204 virtual void TryError (LPCTSTR format, ...);
205 virtual void TryFatal (LPCTSTR format, ...);
206
207 // 通用輔助方法
208 virtual BOOL HasInited () const = 0; // 是否已經初始化
209 virtual BOOL IsPrint2File () const = 0; // 是否把日志輸出到文件
210 virtual BOOL IsPrint2Screen () const = 0; // 是否把日志輸出到屏幕窗口
211 virtual int GetPrintFlag () const = 0; // 打印標志
212 virtual LogLevel GetLogLevel () const = 0; // 日志級別
213 virtual LPCTSTR GetLogFile() const = 0; // 日志文件
214 virtual ErrorCode GetLastError() const = 0; // 當前操作錯誤碼
215
216 /****************************** GUI ******************************/
217 #ifdef _WINDOWS
218 public:
219 // 設置接收日志信息的窗口, hWndGUI == NULL 則取消接收
220 virtual void SetGUIWindow(HWND hWndGUI) = 0;
221 // 獲取接收日志信息的窗口
222 virtual HWND GetGUIWindow() = 0;
223
224 // 銷毀在發送 LOG_MESSAGE 消息時動態創建的 TLogMsg 對象
225 virtual void FreeLogMsg(const TLogMsg* pLogMsg);
226
227 // 虛擬窗口句柄標掩碼:用於向 GUI 窗口發送 LOG_MESSAGE 消息時作為發送源標識
228 static const int LOGGER_FAKE_WINDOW_BASE = 0X80001111;
229 // 自定義日志消息:通過本消息向 GUI 窗口發送日志
230 // 其中:WPARAM -> ILogger 對象指針,LPARAM -> TLogMsg 結構體指針
231 static const int LOG_MESSAGE = WM_USER | (0x7FFF & LOGGER_FAKE_WINDOW_BASE);
232 #endif
233
234 public:
235 static const int PRINT_FLAG_FILE = 0x00000001; // 打印到文件
236 static const int PRINT_FLAG_SCREEN = 0x00000002; // 打印到屏幕
237 static const int DEFAULT_PRINT_FLAG = PRINT_FLAG_FILE; // 默認日志掩碼
238 static const LogLevel DEFAULT_LOG_LEVEL =
239 #ifdef _DEBUG
240 LL_DEBUG
241 #else
242 LL_INFO
243 #endif
244 ;
245 };
246
247 /**************************************************/
248 /************** Logger DLL 導出函數 ***************/
249
250 // 創建 ILogger 對象
251 EXTERN_C LOGGER_API ILogger* ILogger_Create();
252 // 銷毀 ILogger 對象
253 EXTERN_C LOGGER_API void ILogger_Destroy(ILogger* p);
254
255 // 獲取各日志級別的文字描述
256 EXTERN_C LOGGER_API LPCTSTR ILogger_GetLogLevelDesc (ILogger::LogLevel ll);
257 // 獲取各操作錯誤碼的文字描述
258 EXTERN_C LOGGER_API LPCTSTR ILogger_GetErrorDesc (ILogger::ErrorCode ec);
代碼中的注釋基本已經能夠說明日志組件的使用方法,這裡只做一些簡單的概括:
版本:日志組件以 DLL 的形式提供,已編譯成 Debug/Release、MBCS/Unicode、GUI/Console 8個版本
測試:三個測試程序 TestGUILogger、TestDynamicLogger 和 TestConsoleLogger 用於測試所有版本。其中 TestDynamicLogger 采用動態加載方式加載 Logger DLL
使用方法:
0. 應用程序包含 Logger.h 頭文件
1. 調用 ILogger_Create() 導出函數創建 ILogger 對象
2. 調用 ILogger->Init(...) 初始化日志組件
3. 使用 ILogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
4. 調用 ILogger->UnInit(...) 清理日志組件
5. 調用 ILogger_Destroy() 導出函數銷毀 ILogger 對象
2、CStaticLogger:ILogger 包裝器(智能指針)—— 用於靜態加載 Logger DLL
1 #pragma once
2
3 #include "Logger.h"
4
5 /**************************************************/
6 /********* www.2cto.com *********/
7 /********** ILogger 包裝器(智能指針) ***********/
8 /*********** 用於靜態加載 Logger DLL ************/
9
10 class LOGGER_API CStaticLogger
11 {
12 public:
13 // 構造函數:如果 bCreate 為 TRUE,則在構建 CStaticLogger 實例的同時創建 ILogger 對象
14 CStaticLogger(BOOL bCreate = TRUE);
15 // 析構函數
16 ~CStaticLogger();
17 private:
18 CStaticLogger(const CStaticLogger&);
19 CStaticLogger& operator = (const CStaticLogger&);
20
21 public:
22 inline void Reset (ILogger* pLogger); // 重設其封裝的 ILogger 指針
23 inline BOOL IsValid () const; // 判斷其封裝的 ILogger 指針是否非空
24 inline ILogger* Get () const; // 獲取 ILogger 指針
25 inline ILogger& operator * () const; // 獲取 ILogger 引用
26 inline ILogger* operator -> () const; // 獲取 ILogger 指針
27 inline operator ILogger* () const; // 轉換為 ILogger 指針
28
29 private:
30 ILogger* m_pLogger;
31 };
CStaticLogger 為簡化日志組件使用而設計,用於靜態加載 Logger DLL 的場合。使用方法:
0. 應用程序包含 StaticLogger.h 頭文件
1. 創建 CStaticLogger 對象(通常為全局對象)
2. 調用 CStaticLogger->Init(...) 初始化日志組件
3. 使用 CStaticLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
4. 調用 CStaticLogger->UnInit(...) 清理日志組件(CStaticLogger 對象析構時也會自動清理日志組件)
3、CDynamicLogger:ILogger 包裝器(智能指針)—— 用於動態加載 Logger DLL
1 #pragma once
2
3 #include "Logger.h"
4
5 /**************************************************/
6 /********* www.2cto.com/ *********/
7 /************** Logger DLL 默認文件名 ***************/
8
9 #ifdef _DEBUG
10 #ifdef _UNICODE
11 #ifdef _WINDOWS
12 #define DEF_LOGGER_DLL_FILE_PATH _T("Logger_UD.dll")
13 #else
14 #define DEF_LOGGER_DLL_FILE_PATH _T("Logger_CUD.dll")
15 #endif
16 #else
17 #ifdef _WINDOWS
18 #define DEF_LOGGER_DLL_FILE_PATH _T("Logger_D.dll")
19 #else
20 #define DEF_LOGGER_DLL_FILE_PATH _T("Logger_CD.dll")
21 #endif
22 #endif
23 #else
24 #ifdef _UNICODE
25 #ifdef _WINDOWS
26 #define DEF_LOGGER_DLL_FILE_PATH _T("Logger_U.dll")
27 #else
28 #define DEF_LOGGER_DLL_FILE_PATH _T("Logger_CU.dll")
29 #endif
30 #else
31 #ifdef _WINDOWS
32 #define DEF_LOGGER_DLL_FILE_PATH _T("Logger.dll")
33 #else
34 #define DEF_LOGGER_DLL_FILE_PATH _T("Logger_C.dll")
35 #endif
36 #endif
37 #endif
38
39 /**************************************************/
40 /*************** Logger DLL 導出函數 ***************/
41
42 // 創建 ILogger 對象
43 typedef ILogger* (*FN_ILogger_Create) ();
44 // 銷毀 ILogger 對象
45 typedef void (*FN_ILogger_Destroy) (ILogger* p);
46 // 獲取各日志級別的文字描述
47 typedef LPCTSTR (*FN_ILogger_GetLogLevelDesc) (ILogger::LogLevel ll);
48 // 獲取各操作錯誤碼的文字描述
49 typedef LPCTSTR (*FN_ILogger_GetErrorDesc) (ILogger::ErrorCode ec);
50
51 /*************************************************/
52 /********** ILogger 包裝器(智能指針) ***********/
53 /************ 用於動態加載 Logger DLL ************/
54
55 class CDynamicLogger
56 {
57 public:
58 // 構造函數:如果 bLoad 為 TRUE,則在構建 CDynamicLogger 示例的同時創建 ILogger 對象
59 CDynamicLogger(BOOL bLoad = TRUE, LPCTSTR lpszFilePath = DEF_LOGGER_DLL_FILE_PATH)
60 {
61 Reset();
62
63 if(bLoad)
64 Load(lpszFilePath);
65 }
66
67 // 析構函數
68 ~CDynamicLogger()
69 {
70 Free();
71 }
72
73 private:
74 CDynamicLogger(const CDynamicLogger&);
75 CDynamicLogger& operator = (const CDynamicLogger&);
76
77 public:
78 // 創建 ILogger 對象
79 ILogger* ILogger_Create()
80 {return m_fnILoggerCreate();}
81 // 銷毀 ILogger 對象
82 void ILogger_Destroy(ILogger* p)
83 {m_fnILoggerDestroy(p);}
84 // 獲取各日志級別的文字描述
85 LPCTSTR ILogger_GetLogLevelDesc(ILogger::LogLevel ll)
86 {return m_fnILoggerGetLogLevelDesc(ll);}
87 // 獲取各操作錯誤碼的文字描述
88 LPCTSTR ILogger_GetErrorDesc(ILogger::ErrorCode ec)
89 {return m_fnILoggerGetErrorDesc(ec);}
90
91 // 加載 Logger DLL
92 BOOL Load(LPCTSTR lpszFilePath = DEF_LOGGER_DLL_FILE_PATH)
93 {
94 if(IsValid())
95 return FALSE;
96
97 BOOL isOK = FALSE;
98 m_hLogger = ::LoadLibrary(lpszFilePath);
99
100 if(m_hLogger)
101 {
102 m_fnILoggerCreate = (FN_ILogger_Create) ::GetProcAddress(m_hLogger, "ILogger_Create");
103 m_fnILoggerDestroy = (FN_ILogger_Destroy) ::GetProcAddress(m_hLogger, "ILogger_Destroy");
104 m_fnILoggerGetLogLevelDesc = (FN_ILogger_GetLogLevelDesc) ::GetProcAddress(m_hLogger, "ILogger_GetLogLevelDesc");
105 m_fnILoggerGetErrorDesc = (FN_ILogger_GetErrorDesc) ::GetProcAddress(m_hLogger, "ILogger_GetErrorDesc");
106
107 if(m_fnILoggerCreate && m_fnILoggerDestroy)
108 {
109 m_pLogger = ILogger_Create();
110 isOK = (m_pLogger != NULL);
111 }
112 }
113
114 if(!isOK)
115 Free();
116
117 return isOK;
118 }
119
120 // 卸載 Logger DLL
121 BOOL Free()
122 {
123 if(!IsValid())
124 return TRUE;
125
126 BOOL isOK = TRUE;
127
128 if(m_pLogger) ILogger_Destroy(m_pLogger);
129 if(m_hLogger) isOK = ::FreeLibrary(m_hLogger);
130
131 Reset();
132
133 return isOK;
134 }
135
136 BOOL IsValid () const {return m_pLogger != NULL;} // 判斷其封裝的 ILogger 指針是否非空
137 ILogger* Get () const {return m_pLogger;} // 獲取 ILogger 指針
138 ILogger& operator * () const {return *m_pLogger;} // 獲取 ILogger 引用
139 ILogger* operator -> () const {return m_pLogger;} // 獲取 ILogger 指針
140 operator ILogger* () const {return m_pLogger;} // 轉換為 ILogger 指針
141
142 private:
143 void Reset()
144 {
145 m_hLogger = NULL;
146 m_pLogger = NULL;
147 m_fnILoggerCreate = NULL;
148 m_fnILoggerDestroy = NULL;
149 m_fnILoggerGetLogLevelDesc = NULL;
150 m_fnILoggerGetErrorDesc = NULL;
151 }
152
153 private:
154 HMODULE m_hLogger;
155 ILogger* m_pLogger;
156
157 FN_ILogger_Create m_fnILoggerCreate;
158 FN_ILogger_Destroy m_fnILoggerDestroy;
159 FN_ILogger_GetLogLevelDesc m_fnILoggerGetLogLevelDesc;
160 FN_ILogger_GetErrorDesc m_fnILoggerGetErrorDesc;
161 };
CDynamicLogger 為簡化日志組件使用而設計,用於動態加載 Logger DLL 的場合。使用方法:
0. 應用程序包含 DynamicLogger.h 頭文件
1. 創建 CDynamicLogger 對象(通常為全局對象)
2. 調用 CDynamicLogger->Init(...) 初始化日志組件
3. 使用 CDynamicLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
4. 調用 CDynamicLogger->UnInit(...) 清理日志組件(CDynamicLogger 對象析構時也會自動清理日志組件)
下載地址:http://www.BkJia.com/uploadfile/2012/0705/20120705104838584.zip
作者:怪獸