Windows C++ 應用程序通用日志組件(組件及測試程序下載)


引言

  眾所周知,在調試、跟蹤和執行應用程序的過程中,程序的日志能為這些工作提供大量有價值的運行信息。因此,程序的日志對應用程序的運行、維護至關重要。

  在如何記錄程序日志方面,通常有三種選擇:

  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 - http://www.cnblogs.com/ldcsaa/
  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 /********* http://www.cnblogs.com/ldcsaa/ *********/
 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 /********* http://www.cnblogs.com/ldcsaa/ *********/
  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 對象析構時也會自動清理日志組件) 

 

   (有需要的朋友請輕踩這里,你懂的^_*

 

CodeProject


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM