【转自】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) = ; void AppendString(std::string & message, const char * format, va_list args)
{
size_t size = ;
char * buffer = new char[size]; while ()
{
int n = _vsnprintf(buffer, size, format, args);
// If that worked, return a string.
if ((n > -) && (static_cast<size_t>(n) < size))
{
message.append(buffer);
delete [] buffer;
return;
} // Else try again with more space.
size = (n > -) ? n + : // ISO/IEC 9899:1999
size * ; // 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(, );
} dk::ReleaseLog4cpp(); }

【转】Log4cpp 封装的更多相关文章

  1. log4cpp单例类封装

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  2. 对log4cpp进一步封装

    //Mylog.h如下: #pragma once//#include <iostream>#include <log4cpp/Category.hh>#include < ...

  3. 快速使用Log4Cpp

    封了一下接口,快速使用. 其他的你都不用管了. 这里封装了需要读取外部conf文件配置输出项.否则可以用getInstance初始化日志类 #include "L4Cpp.h" v ...

  4. log4cpp退出时内存泄露的修复方案

    1.缘由 一直对log4cpp非常有好感,就在自己的项目中集成了log4cpp1.1.1版本,并围绕着它建立了一系列的封装函数方便外部调用.写完了一个测试代码后,忽然想看看自己写的程序有没有内存泄露问 ...

  5. C++开源库(一) ----log4cpp详解

    我们在写程序的时候通常会希望将一些信息记录下来,方便我们进行日后的一些信息跟踪,错误排查等等.比如:我们在进行数据库操作的时候,我们通常希望知道现在是程序的哪一部分进行了数据库的操作,所以我们会记录下 ...

  6. log4cpp安装使用

    1. 主页:http://log4cpp.sourceforge.net“Log4cpp is library of C++ classes for flexible logging to files ...

  7. Windows下MinGW跨平台编译和使用log4cpp

    Log4cpp 是C++开源日志库,为 C++ 应用程序开发中提供了日志的追踪和调试功能,基于 LGPL 开源协议,移植自 java 的日志项目 log4j, 并在 api 上保持了一致性. 1. 环 ...

  8. C++ log4cpp使用(转)

    参考文章: 1.常用C++库(1)日志库 https://blog.csdn.net/qilimi1053620912/article/details/87378707 2.一步步入门log4cpp  ...

  9. [C#] 简单的 Helper 封装 -- RegularExpressionHelper

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

随机推荐

  1. 解决如下json格式的字符串不能使用DataContractJsonSerializer序列化和反序列化 分类: JSON 2015-01-28 14:26 72人阅读 评论(0) 收藏

    可以解决如下json格式的字符串不能使用DataContractJsonSerializer反序列化 {     "ss": "sss",     " ...

  2. WEB 中的一些名词解释

    OOP: 面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构. AOP: AOP为Aspect Oriented Programmin ...

  3. 前台 添加引用 iis文件路径

    1. <script src="../../../_layouts/15/JS/jquery-1.7.2.js"></script> 在前台添加的引用与II ...

  4. jQuery AJAX load() 方法

    jQuery load() 方法 jQuery load() 方法是简单但强大的 AJAX 方法. load() 方法从服务器加载数据,并把返回的数据放入被选元素中. 语法: $(selector). ...

  5. java_设计模式_组合模式_Composite Pattern(2016-08-12)

    概念: 组合模式(Composite Pattern)将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性. 有时候又叫做部分-整体模式,它使我们树 ...

  6. 分享一个自己写的基于TP的关系模型

    为了说明问题,假设现在有表test1,test1有从表test2:test1属于test3,test1和test4多对多,关联表test1_test4. 1.定义关系 class Test1Model ...

  7. 添加标签2 jquery 和JS

    TAG添加标签 做了个方法方便调用 一.JS版本 <!DOCTYPE html> <html lang="en"> <head> <met ...

  8. Apache 禁止访问目录

    1.打开apache配置文件httpd.conf 2.找到 <Directory /> Options Indexes AllowOverride None Order allow,den ...

  9. css:中文词不断开,整体换行

    一.问题   关于文字的换行与不换行的问题有些特殊情况,是使用css的word-break等属性实现不了的,下面的情况就证明了: 我们想要的效果是,一个词整体换行或不换行,“兼职测试”可以都换至第二行 ...

  10. The Greate Wall 相关网络知识(一)域名劫持

    什么叫做DNS? DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串 ...