zoukankan      html  css  js  c++  java
  • 【转】Log4cpp 封装

    【转自】http://blog.csdn.net/ylioi/article/details/9049591

    这篇文章对Log4cpp使用了宏定义和类进行封装,非常有借鉴意义。

    log4cpp 是参考 log4j 所写的 c++ 版本的写 log 的库。可以在这里下载  http://log4cpp.sourceforge.net/
     
    我的使用方法是:
    1,定义了一个 _LOG4CPP 宏,用来打开或关闭 log4cpp 的调用,以便在完全不需要 log 的情况下可以运行,例如进行性能测试时;又比如 log4cpp 可能有内存泄露,关闭使用它,可以检查程序其它地方是否有泄露;
     
    2,在写 log 时,自动加上函数名,以方便跟踪运行信息;(在 gcc 可以用可变参数宏定义,vc 中用其它办法,稍后说明)
     
    3,每一个需要写 log 的类,都加上一个静态 log 实例,以方便通过配置,使得相应的 log 可以输出到指定的地方,有利于跟踪特定的运行信息;(如果不在配置文件中指定对应的Category, 则会默认为其生成一个NOTSET级别的Category, 因此对应日志会自动记录到 父Category指定的日志文件中)
     
    4,不直接调用 log4cpp ,而是通过宏定义来使用,原因同1,即有利于关闭 log 功能;
     
    基于以上几点,我写了几个函数及宏定义等,以下逐一说明:
     
    // InitializeLog4cpp 从指定的 log 配置文件中读取信息,并初始化 log4cpp,这个函数在进程的入口处调用
    void InitializeLog4cpp(const std::string & logfile);
     
    // ReleaseLog4cpp 用于释入 log4cpp ,在进程的结束处调用
    void ReleaseLog4cpp();
     
    // 以下宏用于在类中声明一个静态变量,变量名为 "log"
    DECLARE_STATIC_LOG()
     
    // 以下宏用于初如化类中的 log 静态变量
    DEFINE_STATIC_LOG(ClassName)
     
    // 以下是用来写 log 信息的几个宏,严重级别分别为 DEBUG, INFO, NOTICE, ERROR
    LogDebug
    LogInfo
    LogNotice
    LogError
     
    以下先演示一个应用实例:
     
    Demo.h 文件主要内容:
     
    #include "LogUtils.h"
    
    using namespace dk;
    class Demo { public: Demo(); virtual ~Demo(); public: void TestIt(int i, int j); private: DECLARE_STATIC_LOG(); // 静态成员变量声明 };

    Demo.cpp 文件主要内容:

    #include "Demo.h"
    
    
    DEFINE_STATIC_LOG(Demo);  // 静态成员变量初始化
    
    Demo::Demo()
    {
        LogInfo("");
    }
    
    Demo::~Demo()
    {
        LogInfo("");
    }
    
    void Demo::TestIt(int i, int j)
    {
        LogInfo("i=%d, j=%d", i, j); // 支持多参数!
    }

    再写个例子来运行,可以看到类似输出

    [INFO] - Demo::Demo() - 
    [INFO] - Demo::TestIt() - i=1, j=2
    [INFO] - Demo::~Demo() -

    最后附上完整的

    LogUtils.h

    LogUtils.cpp

    LogTracer.h (这个文件是因为 vc 不支持可变参数的宏,所以采用的取巧方法,这方法是从网上搜来的,出处忘了,请见谅。)

    LogUtils.h

    #ifndef _LOG_UTILS_H_
    #define _LOG_UTILS_H_
    
    #include <string>
    #include "LogTracer.h"
    
    #if defined(_LOG4CPP)
    
    #include <log4cpp/Category.hh>
    
    namespace log4cpp
    {
        class Category;
    };
    
    #endif
    
    namespace dk
    {
        // 从指定的配置文件logfile中读取配置信息,并初始化log4cpp,这个函数在进程的入口处调用
        void InitializeLog4cpp(const std::string & logfile); 
        void ReleaseLog4cpp(); // 用于释入 log4cpp ,在进程的结束处调用
    
    #if defined (_LOG4CPP)
        log4cpp::Category & GetLogCategory(const char * categoryName); // 配置文件中需包含名为 dk.categoryName的 category
    #endif
      
    #if defined (_LOG4CPP)
    #    define DECLARE_STATIC_LOG() static log4cpp::Category & log  // 用于初始化类中的 log 静态变量
    #    define DEFINE_STATIC_LOG(ClassName) log4cpp::Category & ClassName::log = GetLogCategory(#ClassName)
    #else // 无操作
    #    define DECLARE_STATIC_LOG() 
    #    define DEFINE_STATIC_LOG(ClassName)
    #endif
    
        void suck(const char * fmt, ...);
    
    // 各日志子类宏定义
    #if defined(_LOG4CPP) && defined(WIN32)
    #     define MakePrefix    std::string(__FUNCTION__).append("() - ")
    #    define LogDebug     (LogDebuger(log, std::string("[DEBUG]").append(MakePrefix)))
    #    define LogInfo        (LogInfoer(log, std::string("[INFO]").append(MakePrefix)))
    #    define LogNotice     (LogNoticer(log, std::string("[NOTICE]").append(MakePrefix)))
    #    define LogError        (LogErrorer(log, std::string("[ERROR]").append(MakePrefix)))
    #elif defined(_LOG4CPP) && !defined(WIN32)
    #    define MakePrefix(fmt)        std::string(__FILE__).append(":s:").append(__FUNCTION__).append("() - ").append(fmt).c_str()
    #    define LogDebug(fmt, ...)    log.debug(MakePrefix(fmt), ##__VA_ARGS__)
    #    define LogInfo(fmt, ...)    log.info(MakePrefix(fmt), ##__VA_ARGS__)
    #    define LogNotice(fmt, ...)    log.notice(MakePrefix(fmt), ##__VA_ARGS__)
    #    define LogError(fmt, ...)    log.error(MakePrefix(fmt), ##__VA_ARGS__)
    #else
    #    define LogDebug    suck
    #    define LogInfo     suck
    #    define LogNotice   suck
    #    define LogError    suck
    #endif
    
    }
    
    #endif

    LogUtils.cpp

    #include "LogUtils.h"
    
    #if defined(_LOG4CPP)
    
    #include <log4cpp/PropertyConfigurator.hh>
    
    // appenders
    
    #include <log4cpp/Appender.hh>
    #include <log4cpp/OstreamAppender.hh>
    #include <log4cpp/FileAppender.hh>
    #include <log4cpp/RollingFileAppender.hh>
    #include <log4cpp/AbortAppender.hh>
    #ifdef WIN32
    #include <log4cpp/Win32DebugAppender.hh>
    #include <log4cpp/NTEventLogAppender.hh>
    #endif
    #include <log4cpp/RemoteSyslogAppender.hh>
    #ifdef LOG4CPP_HAVE_LIBIDSA
    #include <log4cpp/IdsaAppender.hh>
    #endif    // LOG4CPP_HAVE_LIBIDSA
    
    #ifdef LOG4CPP_HAVE_SYSLOG
    #include <log4cpp/SyslogAppender.hh>
    #endif
    
    // layouts
    
    #include <log4cpp/Layout.hh>
    #include <log4cpp/BasicLayout.hh>
    #include <log4cpp/SimpleLayout.hh>
    #include <log4cpp/PatternLayout.hh>
    
    #include <log4cpp/Priority.hh>
    
    #endif
    
    namespace dk
    {
        // 从指定的配置文件logfile中读取配置信息,并初始化log4cpp
        void InitializeLog4cpp(const std::string & logfile)
        {
    
    #if defined(_LOG4CPP)
            try
            { 
                log4cpp::PropertyConfigurator::configure(logfile);
            }
            catch (log4cpp::ConfigureFailure & f)
            {
                std::cerr << "Configure Problem " << f.what() << std::endl;
    
                //#if defined(WIN32)
    
                //        log4cpp::Appender * appender = new log4cpp::Win32DebugAppender("console");    
    
                //#else
    
                log4cpp::Appender * appender = new log4cpp::OstreamAppender("console", &std::cout);
                //#endif
    
    
                log4cpp::PatternLayout * patternLayout = new log4cpp::PatternLayout();
                patternLayout->setConversionPattern("%d [%t] %p - %m%n");
    
                appender->setLayout(patternLayout);
    
                log4cpp::Category & root = log4cpp::Category::getRoot();
                root.addAppender(appender);
                root.setPriority(log4cpp::Priority::DEBUG);
            }
    #endif
        }
    
        void ReleaseLog4cpp()
        {
    #if defined(_LOG4CPP)
            log4cpp::Category::shutdown();
    #endif
        }
    
    #if defined(_LOG4CPP)
        log4cpp::Category & GetLogCategory(const char * categoryName)
        {
            std::string name = "Logger."; 
            name.append(categoryName); // 这个name与配置文件相关,如果配置文件中包含了同名的category定义,则使用对应配置;否则将新建一个NOTSET类型的category,并将日志内容存入到Logger指定的输出端里。(因此,配置文件里必须有名为 Logger的category配置)
            log4cpp::Category & category = log4cpp::Category::getInstance(name);
            return category;
        }
    #endif
    
        void suck(const char * fmt, ...)
        {
            if (fmt) {}
        }
    
    }

    LogTracer.h

    #ifndef _LOG_TRACER_H_
    #define _LOG_TRACER_H_
    
    // 开启 日志记录 宏定义
    #define _LOG4CPP
    
    #if defined(_LOG4CPP) && defined(WIN32)
    
    #include <log4cpp/Category.hh>
    
    namespace log4cpp
    {
        class Category;
    };
    
    namespace dk
    {
    
    #include <stdarg.h>
    #include <stdio.h>
    
        class LogTracer
        {
        public:
            LogTracer(log4cpp::Category & log, const std::string & prefix)
                : mLog(log), mMsg(prefix)
            {}
    
            void operator()(const char * fmt, ...)
            {
                va_list ap;
                va_start(ap, fmt);
                AppendString(mMsg, fmt, ap);
                WriteLog(mMsg);
                va_end(ap);
            }
    
        private:
            virtual void WriteLog(const std::string & message) = 0;
    
            void AppendString(std::string & message, const char * format, va_list args)
            {
                size_t size = 1024;
                char * buffer = new char[size];
    
                while (1)
                {
                    int n = _vsnprintf(buffer, size, format, args);
                    // If that worked, return a string.
                    if ((n > -1) && (static_cast<size_t>(n) < size))
                    {
                        message.append(buffer);
                        delete [] buffer;
                        return;
                    }
    
                    // Else try again with more space.
                    size = (n > -1) ? n + 1 : // ISO/IEC 9899:1999
                            size * 2; // twice the old size
                    delete [] buffer;
                    buffer = new char[size];
                }
            }
    
        private:
            // copy-constructor and operator=
            LogTracer(const LogTracer &);
            LogTracer & operator=(const LogTracer &);
    
        protected:
            log4cpp::Category & mLog;
            std::string mMsg;
        };
    
        class LogDebuger : public LogTracer
        {
        public:
            LogDebuger(log4cpp::Category & log, const std::string & prefix)
                : LogTracer(log, prefix)
            {
            }
    
        private:
            virtual void WriteLog(const std::string & message)
            {
                mLog.debug(message);
            }
        };
    
        class LogInfoer : public LogTracer
        {
        public:
            LogInfoer(log4cpp::Category & log, const std::string & prefix)
                : LogTracer(log, prefix)
            {
            }
    
        private:
            virtual void WriteLog(const std::string & message)
            {
                mLog.info(message);
            }
        };
    
        class LogNoticer : public LogTracer
        {
        public:
            LogNoticer(log4cpp::Category & log, const std::string & prefix)
                : LogTracer(log, prefix)
            {
            }
    
        private:
            virtual void WriteLog(const std::string & message)
            {
                mLog.notice(message);
            }
        };
    
        class LogErrorer : public LogTracer
        {
        public:
            LogErrorer(log4cpp::Category & log, const std::string & prefix)
                : LogTracer(log, prefix)
            {
            }
    
        private:
            virtual void WriteLog(const std::string & message)
            {
                mLog.error(message);
            }
        };
    
    }
    
    #endif
    #endif

     log4cpp.Logger.property  配置文件示例

    # property configurator test file
    
    log4cpp.rootCategory=DEBUG, rootAppender
    log4cpp.category.Logger= DEBUG, A1
    
    log4cpp.appender.rootAppender=ConsoleAppender
    log4cpp.appender.rootAppender.layout=BasicLayout
    
    log4cpp.appender.A1=FileAppender
    log4cpp.appender.A1.fileName=Log\Visualization.log
    log4cpp.appender.A1.layout=PatternLayout
    log4cpp.appender.A1.layout.ConversionPattern=%d %m %n

    调用示例:

    #include "LogUtils.h"
    #include "Demo.h"
    
    int main(int argc, char *argv[])
    {
       
        dk::InitializeLog4cpp("Log\log4cpp.Logger.property");
       
        {
            Demo d;
            d.TestIt(1, 4);  
        }
    
        dk::ReleaseLog4cpp();
    
    }
  • 相关阅读:
    Vue异步数据交互 promise axios async fetch
    JS数组或对象转为JSON字符换 JavaScript JSON.stringify()
    JS返回数组的最大值与最小值
    Error: Cannot find module './application'
    Express框架
    NodeJS项目制作流程
    模板引擎art-template
    基于NodeJS的网络响应原理与HTTP协议
    leetcode 953. 验证外星语词典 做题笔记
    leetcode 771. 宝石与石头 做题笔记
  • 原文地址:https://www.cnblogs.com/wenshanzh/p/3511505.html
Copyright © 2011-2022 走看看