【轉自】http://blog.csdn.net/ylioi/article/details/9049591c++
這篇文章對Log4cpp使用了宏定義和類進行封裝,很是有借鑑意義。app
#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(); }