log4cpp 是参考 log4j 所写的 c++ 版本的写 log 的库。可以在这里下载
http://log4cpp.sourceforge.net/
我的使用方法是:
1,定义了一个 _LOG4CPP 宏,用来打开或关闭 log4cpp 的调用,以便在完全不需要 log 的情况下可以运行,例如进行性能测试时;又比如 log4cpp 可能有内存泄露,关闭使用它,可以检查程序其它地方是否有泄露;
2,在写 log 时,自动加上函数名,以方便跟踪运行信息;(在 gcc 可以用可变参数宏定义,vc 中用其它办法,稍后说明)
3,每一个需要写 log 的类,都加上一个静态 log 实例,以方便通过配置,使得相应的 log 可以输出到指定的地方,有利于跟踪特定的运行信息;
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"
namespace dk {
class Demo { public: Demo(); virtual ~Demo(); public: void TestIt(int i, int j);
private: DECLARE_STATIC_LOG();
};
}
|
Demo.cpp 文件主要内容:
#include "Demo.h"
namespace dk {
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 {
void InitializeLog4cpp(const std::string & logfile); void ReleaseLog4cpp();
#if defined (_LOG4CPP) log4cpp::Category & GetLogCategory(const char * categoryName); #endif
#if defined (_LOG4CPP) # define DECLARE_STATIC_LOG() static log4cpp::Category & 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, MakePrefix)) # define LogInfo (LogInfoer(log, MakePrefix)) # define LogNotice (LogNoticer(log, MakePrefix)) # define LogError (LogErrorer(log, MakePrefix)) #elif defined(_LOG4CPP) && !defined(WIN32) # defineMakePrefix(fmt) std::string(__FILE__).append("::").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 { 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 = "dk."; name.append(categoryName);
return log4cpp::Category::getInstance(name); } #endif
void suck(const char * fmt, ...) { if (fmt) {} }
}
|
LogTracer.h
#ifndef _LOG_TRACER_H_ #define _LOG_TRACER_H_
#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-ctor 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
|
封装log4cp p