log4cpp深度封装[通俗易懂]

log4cpp深度封装[通俗易懂]简介关于log4cpp的介绍与好处就不再赘言了,百度一搜一大把。主要是对于log4cpp的使用如果不封装一下,感觉还是挺麻烦的,例如不少函数名挺长的。所以自己动手把它的日常使用进行了封装,可以让使用log4cpp就像调用一句printf()函数一样简单快捷。封装目标不需要用一次就调用一次getInstance,只需要在main文件中引入一次即可封装成需要使用时只需简短的一举logError(“s

大家好,又见面了,我是你们的朋友全栈君。

简介

关于log4cpp的介绍与好处就不再赘言了,百度一搜一大把。主要是对于log4cpp的使用如果不封装一下,感觉还是挺麻烦的,例如不少函数名挺长的。所以自己动手把它的日常使用进行了封装,可以让使用log4cpp就像调用一句printf()函数一样简单快捷。

封装目标

  1. 不需要用一次就调用一次getInstance,只需要在main文件中引入一次即可
  2. 封装成需要使用时只需简短的一举logError(“somelog”) 就搞定
  3. 输出的日志内容包含:文件名,函数名,行号(通过以上函数调用即可)
  4. 利用单例模式封装

具体实现

类定义 & 宏定义

巧妙的使用宏定义可以缩短函数调用形式(虽然effective c++ 和google C++编程规范都极力反对使用太多宏)

#ifndef _MYLOG_H
#define _MYLOG_H

#include<log4cpp/Category.hh>
#include<iostream>

//日志优先级
enum Priority {
    ERROR,
    WARN,
    INFO,
    DEBUG
};

//用单例模式封装log4cpp
class Mylog {
 public: 
    static Mylog& getInstance();
    static void destory();

    void setPriority(Priority priority);
    void error(const char* msg);
    void warn(const char* msg);
    void info(const char* msg);
    void debug(const char* msg);

 private:
    Mylog();  //单例模式:构造函数私有化

 private:
    static Mylog *plog_;
    log4cpp::Category &category_ref_;
};

//*****************************************************
//注意:
//文件名 __FILE__ ,函数名 __func__ ,行号__LINE__ 是编译器实现的
//并非C++头文件中定义的 
//前两个变量是string类型,且__LINE__是整形,所以需要转为string类型
//******************************************************

//整数类型文件行号 ->转换为string类型
inline std::string int2string(int line) {
    std::ostringstream oss;
    oss << line;
    return oss.str();
}


//定义一个在日志后添加 文件名 函数名 行号 的宏定义
#define suffix(msg) std::string(msg).append(" ##")\
        .append(__FILE__).append(":").append(__func__)\
        .append(":").append(int2string(__LINE__))\
        .append("##").c_str()


//不用每次使用时写 getInstance语句
//只需要在主函数文件中写: #define _LOG4CPP_即可在整个程序中使用
#ifdef _LOG4CPP_
Mylog &log = Mylog::getInstance();
#else
extern Mylog &log;
#endif

//缩短并简化函数调用形式
#define logError(msg) log.error(suffix(msg))
#define logWarn(msg) log.warn(suffix(msg))
#define logInfo(msg) log.info(suffix(msg))
#define logDebug(msg) log.debug(suffix(msg))

#endif

成员函数的实现:

#include<iostream>
#include "Mylog.h"
#include<log4cpp/PatternLayout.hh>
#include<log4cpp/OstreamAppender.hh>
#include<log4cpp/FileAppender.hh>
#include<log4cpp/Priority.hh>

using namespace std;

Mylog* Mylog::plog_ = NULL;

//获取log指针
Mylog& Mylog::getInstance() {
    if ( plog_ == NULL ) {
        plog_ = new Mylog;
    }
    return *plog_;
}


//销毁
void Mylog::destory() {
    if (plog_) {
        plog_->category_ref_.info("Mylog destroy");
        plog_->category_ref_.shutdown();
        delete plog_;
    }
}


//构造函数
Mylog::Mylog(): 
    category_ref_(log4cpp::Category::getRoot()) {
    //自定义输出格式
    log4cpp::PatternLayout *pattern_one =
        new log4cpp::PatternLayout;
    pattern_one->setConversionPattern("%d: %p %c %x:%m%n");

    log4cpp::PatternLayout *pattern_two =
        new log4cpp::PatternLayout;
    pattern_two->setConversionPattern("%d: %p %c %x:%m%n");

    //获取屏幕输出
    log4cpp::OstreamAppender *os_appender = 
        new log4cpp::OstreamAppender("osAppender",&std::cout);
    os_appender->setLayout(pattern_one);

    //获取文件日志输出 ( 日志文件名:mylog.txt )
    log4cpp::FileAppender *file_appender = 
        new log4cpp::FileAppender("fileAppender","mylog.txt");
    file_appender->setLayout(pattern_two);

    category_ref_.setPriority(log4cpp::Priority::DEBUG);
    category_ref_.addAppender(os_appender);
    category_ref_.addAppender(file_appender);

    category_ref_.info("Mylog created!");
}


//设置优先级
void Mylog::setPriority(Priority priority) {
    switch (priority) {
        case (ERROR):
            category_ref_.setPriority(log4cpp::Priority::ERROR);
            break;

        case (WARN):
            category_ref_.setPriority(log4cpp::Priority::WARN);
            break;

        case (INFO):
            category_ref_.setPriority(log4cpp::Priority::INFO);
            break;

        case (DEBUG):
            category_ref_.setPriority(log4cpp::Priority::DEBUG);
            break;

        default:
            category_ref_.setPriority(log4cpp::Priority::DEBUG);
            break;    
    }
}


void Mylog::error(const char* msg) {
    category_ref_.error(msg);
}

void Mylog::warn(const char* msg) {
    category_ref_.warn(msg);
}

void Mylog::info(const char* msg) {
    category_ref_.info(msg);
}

void Mylog::debug(const char* msg) {
    category_ref_.debug(msg);
}

这样就大致完成了满足前述目标的封装了。
假如程序中有一个func.h的头文件,其实现文件时func.cpp,如下所示:

func.h:


#ifndef _FUNC_H
#define _FUNC_H

void func();

#endif

func.cpp:

/*************************************************************************
 > File Name: func.cpp
 > Author: 
 > Mail: 
 > Created Time: Thu 30 Jul 2015 06:54:49 AM PDT
 ************************************************************************/


#include<iostream>
#include "func.h"
#include"Mylog.h"

using namespace std;

void func() {
 logError("hello allen,func() called");
}


测试程序:

只需要在主函数中加入第一行语句 #define LOG4CPP (注意需要在第一行引入)
而其他头文件或实现文件中都不需要再添加任何语句引入log4cpp,都可以畅通无阻地使用了

#define _LOG4CPP_

#include<iostream>
#include "Mylog.h"
#include "func.h"


using namespace std;

int main(void) {
    //Mylog& log = Mylog::getInstance();
    //log.setPriority(ERROR);
    logError("error allen");
    logWarn("warn allen");

    func();


    return 0;
}

运行结果:

这里写图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/158415.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Socket粘包问题「建议收藏」

    Socket粘包问题「建议收藏」什么时候要考虑粘包问题1.:如果利用tcp每次发送数据,就与对方建立连接,然后双方发送完一段数据后,就关闭连接,这样就不会出现粘包问题(因为只有一种包结构,类似于http协议)。关闭连接主要要双方都发送close连接(参考tcp关闭协议)。如:A需要发送一段字符串给B,那么A与B建立连接,然后发送双方都默认好的协议字符如”hellogivemesthabouryourself”,然后

    2022年8月11日
    7
  • DataGrid中DropDownList的动态绑定和触发DropDownList事件[通俗易懂]

    DataGrid中DropDownList的动态绑定和触发DropDownList事件[通俗易懂]我在写DataGrid控件中子控件事件时候,DropDownList的事件相比而言麻烦一点,在此,我简单罗列如下(我在此处为了方便这里都用DataGrid中的隐藏列存储我所要的数据):一、DropDownList的动态绑定,只需在DataGrid1_ItemDataBound的事件中,取出数值进行匹配,便可以了,具体代码如下:二、触发DataGrid中DropDownList的事件前台

    2025年10月30日
    3
  • c#csdn_C++ 教程

    c#csdn_C++ 教程C#是微软于2000年6月发布的一种面向对象的、运行于.NETFramework上的高级程序设计语言。它是第一个面向组件的编程语言,同时也是微软.NETwindows网络框架的主角。从语言风格上来讲,C#受到了C,C++和C#的影响,兼顾了各语言的优点,也对各语言存在的问题进行了改进,因此它是一门很优秀的语言。从目前来看,c#大有赶超JAVA之势,它几乎集中了所有关于软件开发和软件…

    2025年9月23日
    5
  • 一眼看懂map和flatmap的区别

    一眼看懂map和flatmap的区别map的作用很容易理解就是对rdd之中的元素进行逐一进行函数操作映射为另外一个rdd。flatMap的操作是将函数应用于rdd之中的每一个元素,将返回的迭代器的所有内容构成新的rdd。通常用来切分单词。Spark中map函数会对每一条输入进行指定的操作,然后为每一条输入返回一个对象;而flatMap函数则是两个操作的集合——正是“先映射后扁平化”:操作1:同map函数一样:对每一条输入进…

    2022年5月4日
    61
  • 老电脑换Linux系统是否会更快,旧电脑不要装Windows!Bodhi Linux系统,小巧强悍,运行更流畅…

    老电脑换Linux系统是否会更快,旧电脑不要装Windows!Bodhi Linux系统,小巧强悍,运行更流畅…你的旧电脑安装win10还好吗?现在科技发展越来越快,尤其是电脑硬件的更新换代,然而大多数的人都不会因为新产品出来,就将自己才用了两三年的电脑换掉。但是,电脑用久了,终究会变慢,尤其是在Windows系统功能越来愈多,越来越大的情况下,我们还是需要换电脑!不过,你的旧电脑怎么办?卖掉?它的价格分分钟还不如废铁。扔掉?又不太舍得。真是如鸡肋一般,食之无味,弃之可惜!很多人都不知道的是,其实即使是5年…

    2022年6月4日
    107
  • linux进程管理工具_进程管理系统的目标

    linux进程管理工具_进程管理系统的目标引言:    在Linux的内核的五大组成模块中,进程管理模块时非常重要的一部分,它虽然不像内存管理、虚拟文件系统等模块那样复杂,也不像进程间通信模块那样条理化,但作为五大内核模块之一,进程管理对我们理解内核的运作、对于我们以后的编程非常重要。同时,作为五大组成模块中的核心模块,它与其他四个模块都有联系。下面就对进程模块进行想写的介绍,首先要了解进程及其相关的概念。其次介

    2025年10月22日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号