c++ log4cpp的实现 包含使用实例和下载源码

log4cpp源码下载点击此处下载
调用对应宏定义实现日志记录功能
在这里插入图片描述

流程

创建一个Appender,并指定其包含的Layout

从系统中得到Category的根,将Appender添加到该Category中;

设置Category的优先级

记录日志

关闭Category

使用原则

不要手动释放Category、Appender和Layout

同一个Appender不要加入多个Category,否则它会被释放多次从而导致程序崩溃

同一个Layout不要附着到多个Appender上,否则也会被释放多次导致程序崩溃

Layout

每个Appender都设置了一个Layout,用于定义这个Appender日志的格式

设置日志的格式

log4cpp中所有的Layout子类,一共有三个:BasicLayout、PatternLayout和SimpleLayout,其中SimpleLayout并不建议使用,而BasicLayout过于简单,因此如果程序员不自己扩展Layout的话,就只能 使用PatternLayout

SimpleLayout

BasicLayout

BasicLayout是log4cpp内置的一种格式

使用实例
在这里插入图片描述

使用setLayout()来设置BasicLayout,BasicLayout()是无参函数

输出
在这里插入图片描述

PatternLayout

可以自己设定格式

使用setConversionPattern函数来设置日志的输出格式

函数声明

void log4cpp::PatternLayout::setConversionPattern
(const std::string &conversionPattern) throw (ConfigureFailure) [virtual]

函数使用方法

类似C语言中的printf,使用格式化字符串来描述输出格式

  • 格式化字符串具体含义

    %c

    category名

    %d

    日期

    日期可以进一步的设置格式,用花括号包围

    例如

    %d{ &H: %M: %S, %l}

    %d{%d %m %Y %H:%M:%S,%l}

    若不设置具体日期格式,则默认格式为

    “Wed Jan 02 02:03:55 1980”

    %m  //消息
    %n   //换行符
    %p   //优先级名
    %r  //从layout被创建后的毫秒数
    %R  //从1970年1月1日0时开始到目前为止的和秒数
    %u  //进程开始到目前为止的秒数
    %x  //NDC
    

可以将setConversionPattern的参数设置为"%d: %p %c %x: %m%n"

具体含义

“时间: 优先级 Category NDC: 消息 换行”

使用实例

log4cpp::PatternLayout* pLayout = new log4cpp::PatternLayout();
pLayout->serConversionPattern("%d: %p %c %s: %m%n");
osAppender->setLayout(pLayout);//一个appender对应一个Layout

日志对应内容
在这里插入图片描述

Appender

负责指向日志的目的地

  • 按日志的目的地分类

    log4cpp::OstreamAppender

    构造函数原型

    OstreamAppender(const string &name, ostream *stream)
    

    参数列表

    name

    指定OstreamAppender的名称

    stream

    指定它关联的流的指针

    添加Appender

    使用实例

    //首先创建一个Appender
    log4cpp::OstreamAppender& osAppender = 
      new log4cpp::OstreamAppender("osAppender", &cout);
    
    log4cpp::PatternLayout* pLayout = new log4cpp::PatternLayout();
    pLayout->setConversionPattern("%d: %p %c : %m%n");
    osAppender->setLayout(pLayout);
    
    log4cpp::Category& root = log4cpp::Category::getRoot();
    
    log4cpp::Category& infoCategory = root.getInstance("infoCategory");
    //调用addAppender方法添加一个Appender
    infoCategory.addAppender(osAppender);
    infoCategory.setPriority(log4cpp::Priority::INFO);
    //只有优先级高于INFO的元素才能输出
    

    先使用构造函数声明,再添加appender到category中

    OstreamAppender用setLayout()函数设置输出格式

    log4cpp::FileAppender

    构造函数原型

    //使用文件名写入
    FileAppender(const std::string &name, const std::string &fileName, 
    bool append=true, mode_t mode=00644);
    //使用文件描述符写入
    FileAppender(const std::string &name, int fd); 
    

    一般仅使用前两个参数,即“名称”和“日志文件名”,第三个参数指示是否在日志文件后继续记入日志,还是清空原日志文件再记录,第四个参数说明文件的打开方式

    log4cpp::RollingFileAppender

    构造函数原型

    RollingFileAppender (const std::string &name, 
    const std::string &fileName, size_t maxFileSize=10 *1024 *1024, 
    unsigned int maxBackupIndex=1, bool append=true, mode_t mode=00644);
    

    它与FileAppender的创建函数很类似,但是多了两个参数:maxFileSize指出了回卷文件的最大值(单位为byte);maxBackupIndex指出了回卷文件所用的备份文件的最大个数

    备份文件

    用来保存回滚文件中因为空间不足未能记录的日志,备份文件的大小仅比回卷文件的最大值大1kb

    只有一个备份文件装满了,才会创建一个新的备份文件

    如果maxBackupIndex取值为3,则回卷文件会有三个备份文件,其名称分别是rollwxb.log.1,rollwxb.log.2和roolwxb.log.3,大小为101kb。

    如果maxBackupIndex取值为0或者小于0,则回卷文件功能会失效,其表现如同FileAppender一样,不会有大小的限制,这也许是一个bug

    FileAppender和RollingFileAppender之间的关系与区别

    FileAppender和RollingFileAppender是log4cpp中最常用的两个 Appender,其功能是将日志写入文件中。它们之间唯一的区别就是前者会移至在文件中记录日志(直到操作系统承受不了的位置),而后者会在文件长度到达指定值时循环记录日志,文件长度不会超过指定值(默认的指定值是10M byte)

  • 所有可以直接使用的Appender列表

    log4cpp::IdsaAppender

    发送到IDS

    log4cpp::FileAppender

    输出到文件

    log4cpp::RollingFileAppender

    输出到回卷文件,即当文件到达某个大小后回卷

    回卷这个词来自磁带机年代,把”磁带绕回到磁带开始处“

    即到达某个大小后回到文件头写入

    log4cpp::OstreamAppender

    输出到一个ostream类

    log4cpp::RemoteSyslogAppender

    输出到远程syslog服务器

    log4cpp::StringQueueAppender

    输出到内存队列

    将日志记录到一个字符串队列中

    _queue变量是StringQueueAppender类中用于具体存储日志的内存队列

    StringQueueAppender的使用方法与OstreamAppender类似,其创建函数值接受一个参数”名称“,记录完成后需要程序员自己从队列中取出每条日志

    使用实例

    log4cpp::StringQueueAppender* strQAppender = new
        log4cpp::StringQueueAppender("strQAppender");
    strQAppender->serLayout(new log4cpp::BasicLayout);
    
    log4cpp::Category& root = log4cpp::Category::getRoot();
    root.addAppender(strQAppender);
    root.setPriority(log4cpp::Priority::DEBUG);
    
    root.error("Hello log4cpp in a Error Message!");
    root.warn("Hello log4cpp in a Warning Message!");
    
    cout << "Get message from Memory Queue!" << endl;
    cout << "-----------------------------------" << endl;
    queue<string>&myStrQ = strQAppender->getQueue();
    while(!myStrQ.empty())
    {
        cout << myStrQ.front();
        myStrQ.pop();
    }
    
    log4cpp::Category::shutdown();
    return 0;
    

    创建StringQueueAppender,然后添加如类中,最后在用StringQueueAppener的成员函数getQueue()返回数据成员容器queue

    log4cpp::SyslogAppender

    输出到本地syslog

    Syslog是类Unix系统的一个核心服务,用来提供日志服务,在Windows系统中并没有直接提供支持,当然可以用相关工具提供Windows系统中的syslog服务

    log4cpp::Win32DebugAppender

    发送到缺省系统调试器

    log4cpp::NTEventLogAppder

    发送到win事件日志

Category

负责向日志中写入信息

负责记录日志,优先级

当日志的优先级大于等于Category时,该日志才会被记录,否则会被忽略掉

一个Category可以对应多个Appender

一个Appender对应一个Layout

回收空间

函数说明

该函数将会从Category上删除所有的Appender

函数原型

void log4cpp::Category::shutdown();
获取根日志

函数原型

Category & Category::getRoot();
获取子日志

函数原型

Catrgory & Category::getInstance(const std::string &name);
使用实例
#include "log4cpp/Category.hh"
#include "log4cpp/Appender.hh"
#include "log4cpp/FileAppender.hh"
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/Layout.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Priority.hh"

int main(int argc, char** argv) {
  log4cpp::Appender *appender1 = new log4cpp::OstreamAppender("console", &std::cout);
  appender1->setLayout(new log4cpp::BasicLayout());

  log4cpp::Appender *appender2 = new log4cpp::FileAppender("default", "program.log");
  appender2->setLayout(new log4cpp::BasicLayout());

  //获取根日志
  log4cpp::Category& root = log4cpp::Category::getRoot();
  root.setPriority(log4cpp::Priority::WARN);
  root.addAppender(appender1);

  //获取子日志
  log4cpp::Category& sub1 = log4cpp::Category::getInstance(std::string("sub1"));
  sub1.addAppender(appender2);

  // use of functions for logging messages
  root.error("root error");
  root.info("root info");
  sub1.error("sub1 error");
  sub1.warn("sub1 warn");

  // printf-style for logging variables
  root.warn("%d + %d == %s ?", 1, 1, "two");

  // use of streams for logging messages
  root << log4cpp::Priority::ERROR << "Streamed root error";
  root << log4cpp::Priority::INFO << "Streamed root info";
  sub1 << log4cpp::Priority::ERROR << "Streamed sub1 error";
  sub1 << log4cpp::Priority::WARN << "Streamed sub1 warn";

  // or this way:
  root.errorStream() << "Another streamed error";
  
  Category::shutdown();
  return 0;
}

输出

1352973121 ERROR  : root error
1352973121 ERROR sub1 : sub1 error
1352973121 WARN sub1 : sub1 warn
1352973121 WARN  : 1 + 1 == two ?
1352973121 ERROR  : Streamed root error
1352973121 ERROR sub1 : Streamed sub1 error
1352973121 WARN sub1 : Streamed sub1 warn
1352973121 ERROR  : Another streamed error

使用log4cpp::Category::getRoot()可以得到根Category。在大多数情况下,一个应用程序只需要一个日志种类(Category),但是有时也会用到多个Category,此时可以使用根Category的getInstance方法来得到子Category。不同的子Category用于不同的场合。

Priority

每个category都有一个优先级,该优先级可以有setPriority方法设置

设计日志优先级

数字越小,优先级越高

typedef enum {
    EMERG = 0,
    FATAL = 0,
    ALERT = 100,
    CRIT = 200,
    ERROR = 300,
    WARN = 400,
    NOTICE = 500,
    INFO = 600,
    DEBUG = 700,
    NOTSET = 800,
} PriorityLevel;
设置优先级

setPriority函数

setPriority()是category类的成员函数

函数说明

设置日志记录的级别,使得日志只记录优先级比所指定优先级级别更高的记录

函数声明

virtual void setPriority(Priority::Value priority) 
throw (std::invalid_argument)

参数列表

priority

输入形式为:log4cpp::Priority::<优先级>

使用实例

log4cpp::OstreamAppender* osAppender1 = 
    new log4cpp::OstreamAppender("osAppender1", &cout);
osAppender1->setLayout(new log4cpp::BasicLayout());

log4cpp::OstreamAppender* osAppender2 = 
    new log4cpp::OstreamAppender("osAppender2", &cout);
osAppender2->setLayout(new log4cpp::BasicLayout());

log4cpp::Category& root = log4cpp::Category::getRoot();
//设置该Category只记录DEBUG级以上的消息
root.setPriority(log4cpp::Priority::DEBUG);

log4cpp::Category& sub1 = root.getInstance("sub1");
sub1.addAppender(osAppender1);
sub1.setPriority(log4cpp::Priority::DEBUG);
seb1.error("sub error");

Category、Appender和Layout三者的关系

系统中可以有多个Category,它们都是继承自同一个根,每个Category负责记录自己的日志;每个Category可以添加多个Appender,每个Appender指定了一个日志的目的地,例如文件、字符流或者Windows日志,当Category记录一条日志时,该日志被写入所有附加到此Category的Appender;每个Appender都包含一个Layout,该Layout定义了这个Appender上日志的格式

log4cpp的日志记录

函数原型

void debug(const std::string &message) throw();
void info(const std::string &message) throw();
void notice(const std::string &message) throw();
void warn(const std::string &message) throw();
void error(const std::string &message) throw();
void crit(const std::string &message) throw();
void alert(const std::string &message) throw();
void emerg(const std::string &message) throw();
void fatal(const std::string &message) throw();

一个封装好的c++日志类

头文件

mylogger.hpp
#include "log4cpp/Category.hh"
#include "log4cpp/Appender.hh"
#include "log4cpp/RollingFileAppender.hh"
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/Layout.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/PatternLayout.hh"
#include "log4cpp/Priority.hh"
#include <string>
#include <stdio.h>
#include <pthread.h>
#define LOG(level, msg)                     \
    {                                       \
        char _msg[1024];                    \
        sprintf(_msg, "%s [%s@%s,%d] ",        \
            msg, __func__, __FILE__, __LINE__ ); \
        MyLogger::get_MyLogger()->level(_msg);  \
    }

using std::string;
using namespace log4cpp;

class MyLogger {
public:
    static MyLogger * get_MyLogger();
    void Logger_Init();
    void AddAppender(const string & path);
    void SetPriority(Priority::Value priority);
    void warn(const char *msg);
  void error(const char *msg);
  void debug(const char *msg);
  void info(const char *msg);
    static void destroy();
private:
    MyLogger();
    ~MyLogger()
    {}

private:
    static pthread_mutex_t * mutex;
    static MyLogger * _pMylogger;
    Category * root;
};

实现文件

//mylogger.cc
#include "mylogger.hpp"

MyLogger * MyLogger::_pMylogger = nullptr;
pthread_mutex_t * MyLogger::mutex = nullptr;

MyLogger * MyLogger::get_MyLogger() {
    if(mutex == nullptr) {
        mutex = new pthread_mutex_t;
        pthread_mutex_init(mutex, NULL);
    }
    if(_pMylogger == nullptr) {
        pthread_mutex_lock(mutex);
        if(_pMylogger == nullptr) {
            _pMylogger = new MyLogger();
        }
        pthread_mutex_unlock(mutex);
    }
    return _pMylogger;
}

MyLogger::MyLogger() {
    Logger_Init();
    SetPriority(Priority::DEBUG);
}

void MyLogger::Logger_Init() {
    OstreamAppender * OsAppender = new OstreamAppender("console", &std::cout);
    PatternLayout * pLayout = new PatternLayout();
  pLayout->setConversionPattern("%d [%c] [%p] %m%n");
    OsAppender->setLayout(pLayout);
    root = &Category::getRoot();
    root->setAppender(OsAppender);
}

void MyLogger::AddAppender(const string & path) {
    RollingFileAppender * RAppender = new RollingFileAppender("Rollingfile", path);
    PatternLayout * pLayout = new PatternLayout();
  pLayout->setConversionPattern("%d [%c] [%p] %m%n");
    RAppender->setLayout(pLayout);
    root->addAppender(RAppender);
}

void MyLogger::SetPriority(Priority::Value priority) {
    root->setPriority(priority);
}

void MyLogger::warn(const char * msg) {
    root->warn(msg);
}

void MyLogger::error(const char * msg) {
    root->error(msg);
}

void MyLogger::debug(const char * msg) {
    root->debug(msg);
}

void MyLogger::info(const char * msg) {
    root->info(msg);
}

void MyLogger::destroy() {
    if(_pMylogger) {
        Category::shutdown();
        delete _pMylogger;
        delete mutex;
    }
}

测试用例

//main.cc
#include "mylogger.hpp"

int main() {
    MyLogger * mylogger = MyLogger::get_MyLogger();
    mylogger->AddAppender("main.log");
    
    LOG(info, "root info");
    LOG(error, "root error");
    LOG(warn, "root warn");
    LOG(debug, "root debug");
    
    MyLogger::destroy();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值