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


相关推荐

  • python抛出异常和捕获异常_在try块中可以抛出异常吗

    python抛出异常和捕获异常_在try块中可以抛出异常吗PythonLearnPython抛出异常【1】程序运行过程中Python解释器遇到一个错误会停止程序的运行并且提示一些错误信息这个就是异常程序停止并且提示错误信息的动作叫做抛出异常抛出异常原因 主动捕获异常可以增加健壮性抛出异常的种类AssertionError,断言失败抛出异常;AttributeError,找不到属性抛出异常;ValueError,…

    2022年10月18日
    0
  • C/C++读写文本文件、二进制文件「建议收藏」

    C/C++读写文本文件、二进制文件「建议收藏」C语言文本文件读写方式;C语言二进制文件读写方式;CPP文本文件读写方式;CPP二进制文件读写方式;

    2022年6月1日
    54
  • U盘市场调查分析

    U盘市场调查分析U盘市场分析2005年前后,是U盘行业最辉煌的年代,然而随着互联网的普及应用,各种网盘以及智能手机传输越来越方便,给U盘施加了一定的压力。除此之外,近几年移动硬盘迅速兴起,更是抢占了大量市场份额,让U盘厂商的日子越来越艰难。但凭借体积小、携带方便、即插即用、稳定等特点,U盘在移动存储领域依然占据着一定优势。面对着各类对手的“围攻”,U盘厂商们一方面升级主流产品,留住客户群,另一方面则纷纷开发细分市场,通过挖掘用户不同领域的需求,以实现新的业务增长。需求下降,U盘行业萎缩 2017年有业内人士发出.

    2022年9月8日
    0
  • 医疗器械进销存软件管理系统_简单仓库管理系统

    医疗器械进销存软件管理系统_简单仓库管理系统开发环境:Eclipse/MyEclipse、Tomcat8、Jdk1.8数据库:MySQL适用于:课程设计,毕业设计,学习等等系统介绍有偿

    2022年9月4日
    3
  • 命令行中 javac、java、javap 的使用详解

    命令行中 javac、java、javap 的使用详解进入命令窗口,若要切换到指定目录,例如E盘下的目录,有2种方法:1)pushd[路径],此命令可将当前目录设为指定的任一个已存在的目录C:\Users\Administrator>pushde:360DownloadsE:\360Downloads>dir//显示当前目录下的目录及文件2)直接先输入e:,然后再用cd切换到指定目录1.javac

    2022年5月28日
    77
  • Django(50)drf异常模块源码分析

    Django(50)drf异常模块源码分析异常模块源码入口APIView类中dispatch方法中的:response=self.handle_exception(exc)源码分析我们点击handle_exception跳转,查看该

    2022年7月30日
    6

发表回复

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

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