zoukankan      html  css  js  c++  java
  • 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 对象析构时也会自动清理日志组件) 

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

    转自:http://www.cnblogs.com/ldcsaa/archive/2012/06/28/2560619.html 


    微信公众号: 猿人谷
    如果您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】
    如果您希望与我交流互动,欢迎关注微信公众号
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

  • 相关阅读:
    matplotlib油漆基础
    使用ant编译项目技能
    [Recompose] Refactor React Render Props to Streaming Props with RxJS and Recompose
    [Recompose] Make Reusable React Props Streams with Lenses
    [Recompose] Compose Streams of React Props with Recompose’s compose and RxJS
    [Recompose] Create Stream Behaviors to Push Props in React Components with mapPropsStream
    [Recompose] Stream Props to React Children with RxJS
    [Recompose] Merge RxJS Button Event Streams to Build a React Counter Component
    [Recompose] Handle React Events as Streams with RxJS and Recompose
    [Recompose] Stream a React Component from an Ajax Request with RxJS
  • 原文地址:https://www.cnblogs.com/heyonggang/p/2831803.html
Copyright © 2011-2022 走看看