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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 程序员计算器在线计算_安卓程序员计算器

    程序员计算器在线计算_安卓程序员计算器在线标准程序员计算器在线标准程序员计算器本工具支持在线提供免费计算器工具,包括标准、科学及程序员计算工具https://tooltt.com/calc/

    2022年8月2日
    6
  • [硬件驱动] CAN接口

    [硬件驱动] CAN接口CAN接口的介绍:CAN总线可分为:高速CAN,低速CAN,单线CAN。1.在速度方面高速CAN的传输速率在125K~~1Mbps。低速CAN的速率在125Kbps以下,低速CAN具更好的容错性。2.这三种总线之间的最主要区别是物理层。以传输介质和线的数量说,单线CAN只需1条导线,低速容错CAN和高速CAN通过双绞线传输。还有电平的逻辑的区别,定义逻辑为1称作隐性,逻辑为0称作…

    2022年6月18日
    52
  • linux系统重启网卡命令_重启linux网卡

    linux系统重启网卡命令_重启linux网卡在实际工作中,经常会遇到Linux系统进行重启网卡的操作。接下来是小编为大家收集的linux系统重启网卡方法,希望能帮到大家。linux系统重启网卡方法一、servicenetworkrestart1、首先用CRT工具连接到Linux命令行界面。或者进入操作系统界面,选择终端输入。2、如果我们对所有的网卡进行重启操作。可以尝试输入:servicenetworkrestart命令进行操…

    2022年4月19日
    320
  • 常用的DNS列表(亲测可用)

    常用的DNS列表(亲测可用)如果经常遇到这样的问题:浏览器无法打开网站,但是qq、微信是正常使用的,说明DNS有问题。我们知道,默认情况下DNS是自动获取的,通常默认DNS就是路由器,然后由路由器负责向上一级路由查找,但是有时候路由器出现问题就可能造成上面的问题,那么如何一劳永逸的解决上面的问题呢?答案就是修改DNS,在手机、电脑上都可以更改,具体根据机型自行查找资料。以下是一些常用的DNS地址,亲测可用哦~…

    2022年6月9日
    40
  • Pytest(5)美化插件进度条pytest-sugar「建议收藏」

    Pytest(5)美化插件进度条pytest-sugar「建议收藏」前言在我们进行自动化测试的时候,用例往往是成百上千,执行的时间是几十分钟或者是小时级别。有时,我们在调试那么多用例的时候,不知道执行到什么程度了,而pytest-sugar插件能很好解决我们的痛点。

    2022年8月6日
    6
  • lnmp一键安装的卸载

    lnmp一键安装的卸载

    2021年10月13日
    40

发表回复

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

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