Windows C++ 应用程序通用日志组件(组件及测试程序下载)

简介: 引言  众所周知,在调试、跟踪和执行应用程序的过程中,程序的日志能为这些工作提供大量有价值的运行信息。因此,程序的日志对应用程序的运行、维护至关重要。  在如何记录程序日志方面,通常有三种选择:  1、采用Log4CXX等公共开源日志组件:这类日志组件的特点是跨平台且功能比较强大,例如可以把日志发往另一台服务器或记录到数据库中等;另外,可配置性较高,可以通过配置文件或程序代码对日志进行很多个性化设置。

引言

  众所周知,在调试、跟踪和执行应用程序的过程中,程序的日志能为这些工作提供大量有价值的运行信息。因此,程序的日志对应用程序的运行、维护至关重要。

  在如何记录程序日志方面,通常有三种选择:

  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 对象析构时也会自动清理日志组件) 

 

   (有需要的朋友请轻踩这里,你懂的^_*

 

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
27天前
|
存储 缓存 算法
【C/C++ 性能优化】提高C++程序的缓存命中率以优化性能
【C/C++ 性能优化】提高C++程序的缓存命中率以优化性能
113 0
|
1月前
|
编译器 Linux C++
3C++程序的编写和实现
3C++程序的编写和实现
17 2
|
16天前
|
人工智能 机器人 C++
【C++/Python】Windows用Swig实现C++调用Python(史上最简单详细,80岁看了都会操作)
【C++/Python】Windows用Swig实现C++调用Python(史上最简单详细,80岁看了都会操作)
|
22天前
|
存储 缓存 C++
C++链表常用的函数编写(增查删改)内附完整程序
C++链表常用的函数编写(增查删改)内附完整程序
|
1月前
|
缓存 编译器 程序员
C/C++编译器并行优化技术:并行优化针对多核处理器和多线程环境进行优化,以提高程序的并行度
C/C++编译器并行优化技术:并行优化针对多核处理器和多线程环境进行优化,以提高程序的并行度
62 0
|
1月前
|
缓存 编译器 程序员
C/C++编译器全局优化技术:全局优化是针对整个程序进行的优化,包括函数之间的优化
C/C++编译器全局优化技术:全局优化是针对整个程序进行的优化,包括函数之间的优化
27 0
|
1月前
|
缓存 算法 编译器
C/C++编译器内存优化技术:内存优化关注程序对内存的访问和使用,以提高内存访问速度和减少内存占用。
C/C++编译器内存优化技术:内存优化关注程序对内存的访问和使用,以提高内存访问速度和减少内存占用。
39 0
|
1月前
|
自然语言处理 编译器 调度
深入gcc编译器:C/C++代码如何变为可执行程序
深入gcc编译器:C/C++代码如何变为可执行程序
77 0
|
1月前
|
并行计算 安全 编译器
【C/C++ 编译相关 gcc】一次搞懂GCC编译选项:优化代码、调试程序必备!
【C/C++ 编译相关 gcc】一次搞懂GCC编译选项:优化代码、调试程序必备!
35 0
|
1月前
|
Web App开发 前端开发 测试技术
Web应用程序测试工具Selenium用法详解
Web应用程序测试工具Selenium用法详解
37 0

热门文章

最新文章