基于Windows C++ 應(yīng)用程序通用日志組件的使用詳解
引言
在如何記錄程序日志方面,通常有三種選擇:
1、采用Log4CXX等公共開源日志組件:這類日志組件的特點(diǎn)是跨平臺且功能比較強(qiáng)大,例如可以把日志發(fā)往另一臺服務(wù)器或記錄到數(shù)據(jù)庫中等;另外,可配置性較高,可以通過配置文件或程序代碼對日志進(jìn)行很多個性化設(shè)置。但從另外一個角度看,由于這些優(yōu)點(diǎn)往往也導(dǎo)致了在使用方面的缺點(diǎn)。首先,對于一般應(yīng)用程序來說,它們并不需要太多的功能,通常只需要把日志記錄到文件或反饋到應(yīng)用程序,功能太多反正讓用戶使用起來覺得繁瑣還得背負(fù)很多從來都用不到的代碼。其次,這類日志組件通常是跨平臺的,并不只是針對 Windows 或 VC 的應(yīng)用程序,因此使用起來總會覺得有點(diǎn)別扭,例如他們的字符都是用 char 類型的,對于一個 Unicode 程序來說每次寫日志都要做字符轉(zhuǎn)換是很不爽的事情,本座在多年前曾經(jīng)使用過 Log4Cpp ,程序執(zhí)行時總是報告日志組件有內(nèi)存泄露,雖然有可能是誤報,但是使用起來總覺得很不舒服。
2、自己寫幾個簡單的類或函數(shù)記錄日志:這種方法的確很簡單,通常都不用一兩百行的代碼。但這種方法通常缺乏規(guī)范性和通用性,其他程序需要記錄類似的但有點(diǎn)差異的日志時,通常的作法是:Copy-Paste-Modify;另外,這類方法很可能也沒有考慮性能或并發(fā)方面的問題,通常是直接在工作線程中寫日志,對于那些性能要求較高的應(yīng)用程序是絕對不允許的。
3、干脆不記錄任何日志:的確,現(xiàn)在很多程序由于各種原因并沒有記錄任何日志。但本座以為,如果一個程序是有用的,具備一定功能,并且需要連續(xù)運(yùn)行較長一段時間,那么記錄日志是必須的;否則,得認(rèn)真考慮該程序是否有存在的必要了。
設(shè)計
綜上所述,編寫一個通用的日志組件應(yīng)該著重考慮三個方面:功能、可用性和性能。下面,本座詳細(xì)說明在設(shè)計日志組件時對這些方面問題的考慮:
1、功能:本日志組件的目的是滿足大多數(shù)應(yīng)用程序記錄日志的需求 —— 把日志輸出到文件或發(fā)送到應(yīng)用程序中,并不提供一些復(fù)雜但不常用的功能。本日志組件的功能包括:
把日志信息輸出到指定文件
每日生成一個日志文件
對于 GUI 程序,可以把日志信息發(fā)送到指定窗口
對于Console應(yīng)用程序,可以把日志信息發(fā)往標(biāo)準(zhǔn)輸出 (std::cout)
支持 MBCS / UNICODE,Console / GUI 程序
支持動態(tài)加載和靜態(tài)加載日志組件 DLL
支持 DEBUG/TRACE/INFO/WARN/ERROR/FATAL 等多個日志級別
2、可用性:本日志組件著重考慮了可用性,盡量讓使用者用起來覺得簡便、舒心:
簡單純凈:不依賴任何程序庫或框架
使用接口簡單,不需復(fù)雜的配置或設(shè)置工作
提供 CStaticLogger 和 CDynamicLogger 包裝類用于靜態(tài)或動態(tài)加載以及操作日志組件,用戶無需關(guān)注加載細(xì)節(jié)
程序如果要記錄多個日志文件只需為每個日志文件創(chuàng)建相應(yīng)的 CStaticLogger 或 CDynamicLogger 對象
只需調(diào)用 Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法記錄日志
日志記錄方法支持可變參數(shù)
日志輸出格式:<時間> <線程ID> <日志級別> <日志內(nèi)容>
3、性能:性能是組件是否值得使用的硬指標(biāo),本組件從設(shè)計到編碼的過程都盡量考慮到性能優(yōu)化:
支持多線程同時發(fā)送寫日志請求
使用單獨(dú)線程在后臺寫日志,不影響工作線程的正常執(zhí)行
采用批處理方式批量記錄日志
接口
1、ILogger:日志組件對象接口
/******************************************************************************
Module: Logger.h
Notices: Copyright (c) 2012 Bruce Liang - http://www.cnblogs.com/ldcsaa/
Purpose: 記錄程序日志。
1. 把日志信息輸出到指定文件
2. 對于 GUI 程序,可以把日志信息發(fā)送到指定窗口
3. 對于Console應(yīng)用程序,可以把日志信息發(fā)往標(biāo)準(zhǔn)輸出 (std::cout)
Desc:
1、功能:
--------------------------------------------------------------------------------------
a) 把日志信息輸出到指定文件
b) 每日生成一個日志文件
c) 對于 GUI 程序,可以把日志信息發(fā)送到指定窗口
d) 對于Console應(yīng)用程序,可以把日志信息發(fā)往標(biāo)準(zhǔn)輸出 (std::cout)
e) 支持 MBCS / UNICODE,Console / GUI 程序
f) 支持動態(tài)加載和靜態(tài)加載日志組件 DLL
g) 支持 DEBUG/TRACE/INFO/WARN/ERROR/FATAL 等多個日志級別
2、可用性:
--------------------------------------------------------------------------------------
a) 簡單純凈:不依賴任何程序庫或框架
b) 使用接口簡單,不需復(fù)雜的配置或設(shè)置工作
c) 提供 CStaticLogger 和 CDynamicLogger 包裝類用于靜態(tài)或動態(tài)加載以及操作日志組件,用戶無需關(guān)注加載細(xì)節(jié)
d) 程序如果要記錄多個日志文件只需為每個日志文件創(chuàng)建相應(yīng)的 CStaticLogger 或 CDynamicLogger 對象
e) 只需調(diào)用 Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法記錄日志
f) 日志記錄方法支持可變參數(shù)
g) 日志輸出格式:<時間> <線程ID> <日志級別> <日志內(nèi)容>
3、性能:
--------------------------------------------------------------------------------------
a) 支持多線程同時發(fā)送寫日志請求
b) 使用單獨(dú)線程在后臺寫日志,不影響工作線程的正常執(zhí)行
c) 采用批處理方式批量記錄日志
Usage:
方法一:(靜態(tài)加載 Logger DLL)
--------------------------------------------------------------------------------------
0. 應(yīng)用程序包含 StaticLogger.h 頭文件
1. 創(chuàng)建 CStaticLogger 對象(通常為全局對象)
2. 調(diào)用 CStaticLogger->Init(...) 初始化日志組件
3. 使用 CStaticLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
4. 調(diào)用 CStaticLogger->UnInit(...) 清理日志組件(CStaticLogger 對象析構(gòu)時也會自動清理日志組件)
方法二:(動態(tài)加載 Logger DLL)
--------------------------------------------------------------------------------------
0. 應(yīng)用程序包含 DynamicLogger.h 頭文件
1. 創(chuàng)建 CDynamicLogger 對象(通常為全局對象)
2. 調(diào)用 CDynamicLogger->Init(...) 初始化日志組件
3. 使用 CDynamicLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
4. 調(diào)用 CDynamicLogger->UnInit(...) 清理日志組件(CDynamicLogger 對象析構(gòu)時也會自動清理日志組件)
方法三:(直接用導(dǎo)出函數(shù)加載 Logger DLL)
--------------------------------------------------------------------------------------
0. 應(yīng)用程序包含 Logger.h 頭文件
1. 手工調(diào)用 ILoger_Create() 和 ILoger_Create() 導(dǎo)出函數(shù)創(chuàng)建和銷毀 ILogger 對象
(注:如果是動態(tài)加載,需手工調(diào)用 ::LoadLibrary()/::FreeLibrary() 系列 API 函數(shù)加載和卸載 Logger DLL)
[
***** 對于希望通過窗口接收日志信息的 GUI 程序 *****
A. 日志組件初始化成功后調(diào)用 SetGUIWindow(HWND) 設(shè)置收日志的窗口
B. 窗口須響應(yīng)處理 LOG_MESSAGE 消息
C. 處理完 LOG_MESSAGE 消息后,調(diào)用 ILogger::FreeLogMsg() 銷毀接收到的 TLogMsg
]
Environment:
1. Windows 2000 or later (_WIN32_WINNT >= 0x0500)
2. VC++ 2010 or later
Release:
1. Logger_C.dll - Console/MBCS/Release
2. Logger_CD.dll - Console/MBCS/Debug
3. Logger_CU.dll - Console/Unicode/Release
4. Logger_CUD.dll - Console/Unicode/Debug
5. Logger.dll - GUI/MBCS/Release
6. Logger_D.dll - GUI/MBCS/Debug
7. Logger_U.dll - GUI/Unicode/Release
8. Logger_UD.dll - GUI/Unicode/Debug
Examples:
1. TestGUILogger - GUI 版測試程序 (靜態(tài)加載)
2. TestDynamicLogger - GUI 版測試程序 (動態(tài)加載)
3. TestConsoleLogger - Console 版測試程序 (靜態(tài)加載)
******************************************************************************/
#pragma once
/**************************************************/
/********** imports / exports Logger.dll **********/
#ifdef LOGGER_EXPORTS
#define LOGGER_API __declspec(dllexport)
//#define TRY_INLINE inline
#else
#define LOGGER_API __declspec(dllimport)
//#define TRY_INLINE
#endif
/**************************************************/
/****************** 日志組件接口 *******************/
class LOGGER_API ILogger
{
public:
/***** 日志級別 *****/
enum LogLevel
{
LL_NONE = 0XFF,
LL_DEBUG = 1,
LL_TRACE = 2,
LL_INFO = 3,
LL_WARN = 4,
LL_ERROR = 5,
LL_FATAL = 6
};
/***** 操作錯誤碼 *****/
enum ErrorCode
{
// 無錯誤
EC_OK = NO_ERROR,
// 文件操作相關(guān)的錯誤
EC_FILE_GENERIC,
EC_FILE_FILENOTFOUND,
EC_FILE_BADPATH,
EC_FILE_TOMANYOPERFILES,
EC_FILE_ACCESSDENIED,
EC_FILE_INVALIDFILE,
EC_FILE_REMOVECURRENTDIR,
EC_FILE_DIRECTORYFULL,
EC_FILE_BADSEEK,
EC_FILE_HARDIO,
EC_FILE_SHARINGVIOLATION,
EC_FILE_LOCKVIOLATION,
EC_FILE_DISKFULL,
EC_FILE_ENDOFFILE,
// 其他錯誤
EC_INVALID_STATE,
EC_INIT_LOGLEVEL,
EC_INIT_PRINTFLAG,
EC_INIT_CREATE_LOG_THREAD_FAIL
};
/******************************************
日志信息結(jié)構(gòu)
*******************************************/
struct TLogMsg
{
DWORD m_dwSize; // 結(jié)構(gòu)大小 - 跟據(jù)消息長度動態(tài)變化
LogLevel m_logLevel; // 日志級別
UINT m_uiThreadID; // 線程ID
SYSTEMTIME m_stMsgTime; // 記錄時間
TCHAR m_psMsg[1]; // 消息內(nèi)容
};
public:
ILogger(void);
virtual ~ILogger(void);
private:
ILogger(const ILogger&);
ILogger& operator = (const ILogger&);
public:
// 日志組件初始化方法
virtual BOOL Init(
LPCTSTR logFile = NULL // 日志文件. 默認(rèn): {AppPath}/logs/{AppName}-YYYYMMDD.log
, LogLevel ll = DEFAULT_LOG_LEVEL // 日志級別. 默認(rèn): [Debug -> LL_DEBUG] / [Release -> LL_INFO]
, int printFlag = DEFAULT_PRINT_FLAG // 輸出掩碼. 是否輸出到文件和(或)屏幕. 默認(rèn): 只輸出到文件
) = 0;
// 日志組件清理方法
virtual BOOL UnInit() = 0;
public:
// 寫日志方法:傳入日志內(nèi)容字符串(對于不需要格式化的日志文本,用本方法效率最高)
virtual void Log_0 (LogLevel ll, LPCTSTR msg) = 0;
virtual void Debug_0(LPCTSTR msg);
virtual void Trace_0(LPCTSTR msg);
virtual void Info_0 (LPCTSTR msg);
virtual void Warn_0 (LPCTSTR msg);
virtual void Error_0(LPCTSTR msg);
virtual void Fatal_0(LPCTSTR msg);
// 寫日志方法:傳入格式化字符串和參數(shù)棧指針(通常只在組件內(nèi)部使用)
virtual void LogV (LogLevel ll, LPCTSTR format, va_list arg_ptr);
// 寫日志方法:傳入格式化字符串和可變參數(shù)(非常靈活簡便)
virtual void Log (LogLevel ll, LPCTSTR format, ...);
virtual void Debug (LPCTSTR format, ...);
virtual void Trace (LPCTSTR format, ...);
virtual void Info (LPCTSTR format, ...);
virtual void Warn (LPCTSTR format, ...);
virtual void Error (LPCTSTR format, ...);
virtual void Fatal (LPCTSTR format, ...);
// 寫日志方法:傳入格式化字符串和可變參數(shù)(與上一組方法類似,但在進(jìn)行任何操作前會檢查日志級別)
virtual void TryLog (LogLevel ll, LPCTSTR format, ...);
virtual void TryDebug (LPCTSTR format, ...);
virtual void TryTrace (LPCTSTR format, ...);
virtual void TryInfo (LPCTSTR format, ...);
virtual void TryWarn (LPCTSTR format, ...);
virtual void TryError (LPCTSTR format, ...);
virtual void TryFatal (LPCTSTR format, ...);
// 通用輔助方法
virtual BOOL HasInited () const = 0; // 是否已經(jīng)初始化
virtual BOOL IsPrint2File () const = 0; // 是否把日志輸出到文件
virtual BOOL IsPrint2Screen () const = 0; // 是否把日志輸出到屏幕窗口
virtual int GetPrintFlag () const = 0; // 打印標(biāo)志
virtual LogLevel GetLogLevel () const = 0; // 日志級別
virtual LPCTSTR GetLogFile() const = 0; // 日志文件
virtual ErrorCode GetLastError() const = 0; // 當(dāng)前操作錯誤碼
/****************************** GUI ******************************/
#ifdef _WINDOWS
public:
// 設(shè)置接收日志信息的窗口, hWndGUI == NULL 則取消接收
virtual void SetGUIWindow(HWND hWndGUI) = 0;
// 獲取接收日志信息的窗口
virtual HWND GetGUIWindow() = 0;
// 銷毀在發(fā)送 LOG_MESSAGE 消息時動態(tài)創(chuàng)建的 TLogMsg 對象
virtual void FreeLogMsg(const TLogMsg* pLogMsg);
// 虛擬窗口句柄標(biāo)掩碼:用于向 GUI 窗口發(fā)送 LOG_MESSAGE 消息時作為發(fā)送源標(biāo)識
static const int LOGGER_FAKE_WINDOW_BASE = 0X80001111;
// 自定義日志消息:通過本消息向 GUI 窗口發(fā)送日志
// 其中:WPARAM -> ILogger 對象指針,LPARAM -> TLogMsg 結(jié)構(gòu)體指針
static const int LOG_MESSAGE = WM_USER | (0x7FFF & LOGGER_FAKE_WINDOW_BASE);
#endif
public:
static const int PRINT_FLAG_FILE = 0x00000001; // 打印到文件
static const int PRINT_FLAG_SCREEN = 0x00000002; // 打印到屏幕
static const int DEFAULT_PRINT_FLAG = PRINT_FLAG_FILE; // 默認(rèn)日志掩碼
static const LogLevel DEFAULT_LOG_LEVEL =
#ifdef _DEBUG
LL_DEBUG
#else
LL_INFO
#endif
};
/**************************************************/
/************** Logger DLL 導(dǎo)出函數(shù) ***************/
// 創(chuàng)建 ILogger 對象
EXTERN_C LOGGER_API ILogger* ILogger_Create();
// 銷毀 ILogger 對象
EXTERN_C LOGGER_API void ILogger_Destroy(ILogger* p);
// 獲取各日志級別的文字描述
EXTERN_C LOGGER_API LPCTSTR ILogger_GetLogLevelDesc (ILogger::LogLevel ll);
// 獲取各操作錯誤碼的文字描述
EXTERN_C LOGGER_API LPCTSTR ILogger_GetErrorDesc (ILogger::ErrorCode ec);
代碼中的注釋基本已經(jīng)能夠說明日志組件的使用方法,這里只做一些簡單的概括:
版本:日志組件以 DLL 的形式提供,已編譯成 Debug/Release、MBCS/Unicode、GUI/Console 8個版本
測試:三個測試程序 TestGUILogger、TestDynamicLogger 和 TestConsoleLogger 用于測試所有版本。其中 TestDynamicLogger 采用動態(tài)加載方式加載 Logger DLL
使用方法:
0. 應(yīng)用程序包含 Logger.h 頭文件
1. 調(diào)用 ILogger_Create() 導(dǎo)出函數(shù)創(chuàng)建 ILogger 對象
2. 調(diào)用 ILogger->Init(...) 初始化日志組件
3. 使用 ILogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
4. 調(diào)用 ILogger->UnInit(...) 清理日志組件
5. 調(diào)用 ILogger_Destroy() 導(dǎo)出函數(shù)銷毀 ILogger 對象
2、CStaticLogger:ILogger 包裝器(智能指針)—— 用于靜態(tài)加載 Logger DLL
#pragma once
#include "Logger.h"
/**************************************************/
/********* http://www.cnblogs.com/ldcsaa/ *********/
/********** ILogger 包裝器(智能指針) ***********/
/*********** 用于靜態(tài)加載 Logger DLL ************/
class LOGGER_API CStaticLogger
{
public:
// 構(gòu)造函數(shù):如果 bCreate 為 TRUE,則在構(gòu)建 CStaticLogger 實例的同時創(chuàng)建 ILogger 對象
CStaticLogger(BOOL bCreate = TRUE);
// 析構(gòu)函數(shù)
~CStaticLogger();
private:
CStaticLogger(const CStaticLogger&);
CStaticLogger& operator = (const CStaticLogger&);
public:
inline void Reset (ILogger* pLogger); // 重設(shè)其封裝的 ILogger 指針
inline BOOL IsValid () const; // 判斷其封裝的 ILogger 指針是否非空
inline ILogger* Get () const; // 獲取 ILogger 指針
inline ILogger& operator * () const; // 獲取 ILogger 引用
inline ILogger* operator -> () const; // 獲取 ILogger 指針
inline operator ILogger* () const; // 轉(zhuǎn)換為 ILogger 指針
private:
ILogger* m_pLogger;
};
CStaticLogger 為簡化日志組件使用而設(shè)計,用于靜態(tài)加載 Logger DLL 的場合。使用方法:
0. 應(yīng)用程序包含 StaticLogger.h 頭文件
1. 創(chuàng)建 CStaticLogger 對象(通常為全局對象)
2. 調(diào)用 CStaticLogger->Init(...) 初始化日志組件
3. 使用 CStaticLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
4. 調(diào)用 CStaticLogger->UnInit(...) 清理日志組件(CStaticLogger 對象析構(gòu)時也會自動清理日志組件)
3、CDynamicLogger:ILogger 包裝器(智能指針)—— 用于動態(tài)加載 Logger DLL
#pragma once
#include "Logger.h"
/**************************************************/
/********* http://www.cnblogs.com/ldcsaa/ *********/
/************** Logger DLL 默認(rèn)文件名 ***************/
#ifdef _DEBUG
#ifdef _UNICODE
#ifdef _WINDOWS
#define DEF_LOGGER_DLL_FILE_PATH _T("Logger_UD.dll")
#else
#define DEF_LOGGER_DLL_FILE_PATH _T("Logger_CUD.dll")
#endif
#else
#ifdef _WINDOWS
#define DEF_LOGGER_DLL_FILE_PATH _T("Logger_D.dll")
#else
#define DEF_LOGGER_DLL_FILE_PATH _T("Logger_CD.dll")
#endif
#endif
#else
#ifdef _UNICODE
#ifdef _WINDOWS
#define DEF_LOGGER_DLL_FILE_PATH _T("Logger_U.dll")
#else
#define DEF_LOGGER_DLL_FILE_PATH _T("Logger_CU.dll")
#endif
#else
#ifdef _WINDOWS
#define DEF_LOGGER_DLL_FILE_PATH _T("Logger.dll")
#else
#define DEF_LOGGER_DLL_FILE_PATH _T("Logger_C.dll")
#endif
#endif
#endif
/**************************************************/
/*************** Logger DLL 導(dǎo)出函數(shù) ***************/
// 創(chuàng)建 ILogger 對象
typedef ILogger* (*FN_ILogger_Create) ();
// 銷毀 ILogger 對象
typedef void (*FN_ILogger_Destroy) (ILogger* p);
// 獲取各日志級別的文字描述
typedef LPCTSTR (*FN_ILogger_GetLogLevelDesc) (ILogger::LogLevel ll);
// 獲取各操作錯誤碼的文字描述
typedef LPCTSTR (*FN_ILogger_GetErrorDesc) (ILogger::ErrorCode ec);
/*************************************************/
/********** ILogger 包裝器(智能指針) ***********/
/************ 用于動態(tài)加載 Logger DLL ************/
class CDynamicLogger
{
public:
// 構(gòu)造函數(shù):如果 bLoad 為 TRUE,則在構(gòu)建 CDynamicLogger 示例的同時創(chuàng)建 ILogger 對象
CDynamicLogger(BOOL bLoad = TRUE, LPCTSTR lpszFilePath = DEF_LOGGER_DLL_FILE_PATH)
{
Reset();
if(bLoad)
Load(lpszFilePath);
}
// 析構(gòu)函數(shù)
~CDynamicLogger()
{
Free();
}
private:
CDynamicLogger(const CDynamicLogger&);
CDynamicLogger& operator = (const CDynamicLogger&);
public:
// 創(chuàng)建 ILogger 對象
ILogger* ILogger_Create()
{return m_fnILoggerCreate();}
// 銷毀 ILogger 對象
void ILogger_Destroy(ILogger* p)
{m_fnILoggerDestroy(p);}
// 獲取各日志級別的文字描述
LPCTSTR ILogger_GetLogLevelDesc(ILogger::LogLevel ll)
{return m_fnILoggerGetLogLevelDesc(ll);}
// 獲取各操作錯誤碼的文字描述
LPCTSTR ILogger_GetErrorDesc(ILogger::ErrorCode ec)
{return m_fnILoggerGetErrorDesc(ec);}
// 加載 Logger DLL
BOOL Load(LPCTSTR lpszFilePath = DEF_LOGGER_DLL_FILE_PATH)
{
if(IsValid())
return FALSE;
BOOL isOK = FALSE;
m_hLogger = ::LoadLibrary(lpszFilePath);
if(m_hLogger)
{
m_fnILoggerCreate = (FN_ILogger_Create) ::GetProcAddress(m_hLogger, "ILogger_Create");
m_fnILoggerDestroy = (FN_ILogger_Destroy) ::GetProcAddress(m_hLogger, "ILogger_Destroy");
m_fnILoggerGetLogLevelDesc = (FN_ILogger_GetLogLevelDesc) ::GetProcAddress(m_hLogger, "ILogger_GetLogLevelDesc");
m_fnILoggerGetErrorDesc = (FN_ILogger_GetErrorDesc) ::GetProcAddress(m_hLogger, "ILogger_GetErrorDesc");
if(m_fnILoggerCreate && m_fnILoggerDestroy)
{
m_pLogger = ILogger_Create();
isOK = (m_pLogger != NULL);
}
}
if(!isOK)
Free();
return isOK;
}
// 卸載 Logger DLL
BOOL Free()
{
if(!IsValid())
return TRUE;
BOOL isOK = TRUE;
if(m_pLogger) ILogger_Destroy(m_pLogger);
if(m_hLogger) isOK = ::FreeLibrary(m_hLogger);
Reset();
return isOK;
}
BOOL IsValid () const {return m_pLogger != NULL;} // 判斷其封裝的 ILogger 指針是否非空
ILogger* Get () const {return m_pLogger;} // 獲取 ILogger 指針
ILogger& operator * () const {return *m_pLogger;} // 獲取 ILogger 引用
ILogger* operator -> () const {return m_pLogger;} // 獲取 ILogger 指針
operator ILogger* () const {return m_pLogger;} // 轉(zhuǎn)換為 ILogger 指針
private:
void Reset()
{
m_hLogger = NULL;
m_pLogger = NULL;
m_fnILoggerCreate = NULL;
m_fnILoggerDestroy = NULL;
m_fnILoggerGetLogLevelDesc = NULL;
m_fnILoggerGetErrorDesc = NULL;
}
private:
HMODULE m_hLogger;
ILogger* m_pLogger;
FN_ILogger_Create m_fnILoggerCreate;
FN_ILogger_Destroy m_fnILoggerDestroy;
FN_ILogger_GetLogLevelDesc m_fnILoggerGetLogLevelDesc;
FN_ILogger_GetErrorDesc m_fnILoggerGetErrorDesc;
};
CDynamicLogger 為簡化日志組件使用而設(shè)計,用于動態(tài)加載 Logger DLL 的場合。使用方法:
0. 應(yīng)用程序包含 DynamicLogger.h 頭文件
1. 創(chuàng)建 CDynamicLogger 對象(通常為全局對象)
2. 調(diào)用 CDynamicLogger->Init(...) 初始化日志組件
3. 使用 CDynamicLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
4. 調(diào)用 CDynamicLogger->UnInit(...) 清理日志組件(CDynamicLogger 對象析構(gòu)時也會自動清理日志組件)
相關(guān)文章
C++ new/delete相關(guān)知識點(diǎn)詳細(xì)解析
C語言用一堆標(biāo)準(zhǔn)庫函數(shù)malloc和free在自由存儲區(qū)中分配存儲空間,而C++則用new和delete表達(dá)式實現(xiàn)相同的功能2013-09-09全面了解結(jié)構(gòu)體、聯(lián)合體和枚舉類型
下面小編就為大家?guī)硪黄媪私饨Y(jié)構(gòu)體、聯(lián)合體和枚舉類型。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-07-07