【轉】Log4cpp 封裝

【轉自】http://blog.csdn.net/ylioi/article/details/9049591c++

這篇文章對Log4cpp使用了宏定義和類進行封裝,很是有借鑑意義。app

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() -
測試

最後附上完整的spa

LogUtils.h.net

LogUtils.cppdebug

LogTracer.h (這個文件是由於 vc 不支持可變參數的宏,因此採用的取巧方法,這方法是從網上搜來的,出處忘了,請見諒。)
日誌

LogUtils.hcode

#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();

}
相關文章
相關標籤/搜索