log4cpp日志文件(linux环境),C++单例模式完成Mylog的类封装

log4cpp日志文件(linux环境)


一.前言

在使用日志系统log4cpp之前,需要配置好log4cpp的包文件,另外注意在编译的时候,也需要加上-llog4cpp -llpthread语句。
log4cpp配置教程1
log4cpp配置教程2


日志文件中的优先级:
在LINUX的SYSLOG中,对日志内容进行分级,将分为8个级别,如下:
LOG_EMERG 系统不可用
LOG_ALERT 消息需立即处理
LOG_CRIT 重要情况
LOG_ERR 错误
LOG_WARNING 警告
LOG_NOTICE 正常情况,但较为重要
LOG_INFO 信息
LOG_DEBUG 调试信息


二.日志文件

需要添加的头文件:

#include <log4cpp/Category.hh>
#include <log4cpp/BasicLayout.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/RollingFileAppender.hh>
using std::cout;
using namespace log4cpp;

练习0:将日期:信息作为格式, 输出日志信息到cout输出流中
void test0()
{
    //1.单例模式接收一个对象
    Category &infoCategory = Category::getInstance("name");
    //2.这个对象如果想要发出日志信息,那么就需要接上一个appender,appender里面设置了记录格式与信息出口
    OstreamAppender appender("name", &cout);
    PatternLayout *layout = new PatternLayout();
    layout->setConversionPattern("%d: [%p] %m %n");
    appender.setLayout(layout);
    infoCategory.setAppender(appender);
    //3.之后单例对象就可以设置好优先级,当大于等于设置好的级别之后才会发出,不设置的话默认就是Priority::INFO
    infoCategory.setPriority(Priority::WARN);
    //4.发出信息,级别由低到高
    infoCategory.debug("this is a debug message");
    infoCategory.info("this is a info message");
    infoCategory.notice("this is a notice message");
    infoCategory.warn("this is a warning message");
    infoCategory.error("this is a error message");
    infoCategory.crit("this is a critical message");
    infoCategory.alert("this is a alert message");
    infoCategory.emerg("this is a emerge message");

    Category::shutdown();
}

output:

root@linux:/home/wwx/week2/log4cpp# g++ main.cpp -o main -llog4cpp -lpthread -g
root@linux:/home/wwx/week2/log4cpp# ./main
2020-02-28 22:07:12,371: [WARN] this is a warning message 
2020-02-28 22:07:12,371: [ERROR] this is a error message 
2020-02-28 22:07:12,371: [CRIT] this is a critical message 
2020-02-28 22:07:12,371: [ALERT] this is a alert message 
2020-02-28 22:07:12,371: [FATAL] this is a emerge message 

练习1:将日期:信息作为格式, 输出日志信息到cout输出流中
void test1()
{
    Category &infoCategory = Category::getInstance("name");
    OstreamAppender appender("name", &cout);
    appender.setLayout(new BasicLayout());
    infoCategory.setAppender(appender);
    infoCategory.setPriority(Priority::WARN);
    infoCategory.debug("this is a debug message");
    infoCategory.info("this is a info message");
    infoCategory.notice("this is a notice message");
    infoCategory.warn("this is a warning message");
    infoCategory.error("this is a error message");
    infoCategory.crit("this is a critical message");
    infoCategory.alert("this is a alert message");
    infoCategory.emerg("this is a emerge message");

    Category::shutdown();
}

output:

root@linux:/home/wwx/week2/log4cpp# g++ main.cpp -o main -llog4cpp -lpthread -g
root@linux:/home/wwx/week2/log4cpp# ./main
1582898865 WARN name : this is a warning message
1582898865 ERROR name : this is a error message
1582898865 CRIT name : this is a critical message
1582898865 ALERT name : this is a alert message
1582898865 FATAL name : this is a emerge message

练习2:将日期:信息作为格式, 输出日志信息到文件file.log中
void test2()
{
    Category &log = Category::getInstance("log");
    FileAppender appender("appender", "file.log");
    PatternLayout *layout = new PatternLayout();
    layout->setConversionPattern("%d:%m %n");
    appender.setLayout(layout);
    log.setAppender(appender);

    log.debug("this is a debug message");
    log.info("this is a info message");
    log.notice("this is a notice message");
    log.warn("this is a warning message");
    log.error("this is a error message");
    log.crit("this is a critical message");
    log.alert("this is a alert message");
    log.emerg("this is a emerge message");

    Category::shutdown();
}

练习3:回滚文件

回滚文件(RollingFileAppender), 在之前将日志系统输入到file.log的过程中,file.log会一直增大,如果设置成为回滚文件,那么每个文件的大小是固定的,文件回滚则意味着不断对固定大小的文件进行重写,只保留最新的记录

题目:输出100条数据,并分别记录到文件与回滚文件中进行比较。

注意: PatterLayout不能只设置一个layout然后适用于所有的Appender, 必须每一个Appender都设置一个新的layout

 
void test3()
{
    PatternLayout *layout = new PatternLayout();
    layout->setConversionPattern("%d: [%p] %m %n");

    PatternLayout *layout2 = new PatternLayout();
    layout2->setConversionPattern("%d: [%p] %m %n");

    FileAppender fileapp("fileapp", "file.log");
    fileapp.setLayout(layout);

    RollingFileAppender rollfileapp("rollfileapp", "rollfile.log", 1024, 3);
    rollfileapp.setLayout(layout2);

    Category &root = Category::getInstance("root");
    root.setAppender(fileapp);
    root.addAppender(rollfileapp);

    root.setPriority(Priority::DEBUG);
    for (int i = 0; i < 100; i++)
    {
        root.debug("this is a debug message");
        root.info("this is a info message");
        root.notice("this is a notice message");
        root.warn("this is a warning message");
        root.error("this is a error message");
        root.crit("this is a critical message");
        root.alert("this is a alert message");
        root.emerg("this is a emerge message");
    }

    Category::shutdown();
}

小程序:单例模式C++封装Mylog类

Mylog.h:

#ifndef _WD_MYLOG_H_
#define _WD_MYLOG_H_
#include <log4cpp/Category.hh>
#include <log4cpp/BasicLayout.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/RollingFileAppender.hh>
#include <string>
#include <sstream>
#include <iomanip>
using std::setw;
using std::cout;
using std::string;
using std::stringstream;
using namespace log4cpp;

namespace wd
{


//使用单例模式
class Mylog
{
public:
    void warn(const char *msg);
    void error(const char *msg);
    void debug(const char *msg);
    void info(const char *msg);
    static Mylog *getInstance();
    static void destory();

private:
    Mylog();
    ~Mylog();

private:
    static Mylog *_pInstance;
    Category &_root;
};

Mylog *Mylog::getInstance()
{
    if (!_pInstance)
    {
        _pInstance = new Mylog();
    }
    return _pInstance;
}

Mylog::Mylog()
    : _root(Category::getRoot().getInstance("rootCategory"))
{
    OstreamAppender *Osappender = new OstreamAppender("Osappender", &cout);
    PatternLayout *layout1 = new PatternLayout();
    layout1->setConversionPattern("%d: [%p] %m %n");
    Osappender->setLayout(layout1);
    _root.addAppender(Osappender);
    _root.setPriority(Priority::DEBUG);
    _root.info("Mylog()");
}

Mylog::~Mylog()
{
    _root.info("~Mylog()");
}

void Mylog::destory()
{
    if (_pInstance){
        delete _pInstance;
        _pInstance = NULL;
    }
    Category::shutdown();
}


void Mylog::warn(const char *msg)
{
    stringstream ss;
    ss << "\""<< msg << "\"" << setw(10) <<"FileName:" << __FILE__ << setw(10) <<" Function():" << __FUNCTION__ << setw(10) <<" LINE:" << __LINE__;
    _root.warn(ss.str());
}

void Mylog::info(const char *msg)
{
    stringstream ss;
    ss << "\""<< msg << "\"" << setw(10) <<"FileName:" << __FILE__ << setw(10) <<" Function():" << __FUNCTION__ << setw(10) <<" LINE:" << __LINE__;
    _root.info(ss.str());
}

void Mylog::debug(const char *msg)
{
    stringstream ss;
    ss << "\""<< msg << "\"" << setw(10) <<"FileName:" << __FILE__ << setw(10) <<" Function():" << __FUNCTION__ << setw(10) <<" LINE:" << __LINE__;
    _root.debug(ss.str());
}

void Mylog::error(const char *msg)
{
    stringstream ss;
    ss << "\""<< msg << "\"" << setw(10) <<"FileName:" << __FILE__ << setw(10) <<" Function():" << __FUNCTION__ << setw(10) <<" LINE:" << __LINE__;
    _root.error(ss.str());
}


//*************下面将Mylog中的函数直接定义为内联函数,可以直接调用**************//
Mylog *Mylog::_pInstance = NULL;
Mylog *log = Mylog::getInstance();
inline void LogError(const char* msg){log->error(msg);}
inline void LogDebug(const char* msg){log->debug(msg);}
inline void LogInfo(const char* msg){log->info(msg);}
inline void LogWarn(const char* msg){log->warn(msg);}

} // namespace wd



#endif

main.cpp:

#include "Mylog.h"
using namespace wd;


int main(){
    LogError("HelloW");
    LogWarn("wan");
    LogInfo("info");
    return 0;
}



/*
作业要求:
1.输出的日志信息能同时输出到终端和文件
2.输出的日志信息中最好能有文件的名字,函数的名字及其所在的行号
3.使用单例模式
*/

output:

wwx@linux:~/week2/homework6$ g++ main.cpp -o main  -llog4cpp -lpthread -g
wwx@linux:~/week2/homework6$ ./main
2020-03-01 14:26:47,740: [INFO] Mylog() 
2020-03-01 14:26:47,740: [WARN] "HelloW" FileName:Mylogger.h Function():error LINE:100 
2020-03-01 14:26:47,740: [WARN] "wan" FileName:Mylogger.h Function():warn     LINE:79 
2020-03-01 14:26:47,740: [WARN] "info" FileName:Mylogger.h Function():info LINE:86 

小程序版本二:模板参数包重置输出Mylog类

如果想log4cpp输出类似于printf一样的语句,需要用到模板来重新实现:

LogInfo("this is an info message. number = %d, str = %s\n", number, pstr);

下面是改进之后的代码,如果不需要的话,也可以直接就用版本一。
Mylog.h:

#ifndef _WD_MYLOG_H_
#define _WD_MYLOG_H_
#include <log4cpp/Category.hh>
#include <log4cpp/BasicLayout.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/RollingFileAppender.hh>
#include <string>
#include <sstream>
#include <iomanip>
using std::cout;
using std::endl;
using std::setw;
using std::string;
using std::stringstream;
using namespace log4cpp;

namespace wd
{

//****************************定义输出格式Myprintf函数****************************//
void Myprintf(stringstream &ss, const char *str)
{
    ss << str;
}

template <typename T, typename... Args>
void Myprintf(stringstream &ss, const char *str, const T &val, Args... args)
{
    int i = 0;
    while (str[i])
    {
        if (str[i] == '%')
        {
            char c = str[i + 1];
            switch (c)
            {
            case 'd':
                ss << val;
                Myprintf(ss, str + i + 2, args...);
                return;
            case 'c':
                ss << val;
                Myprintf(ss, str + i + 2, args...);
                return;
            case 's':
                ss << val;
                Myprintf(ss, str + i + 2, args...);
                return;
            default:
                ss << "Wrong!Error has happended!" << endl;
                exit(-1);
            }
        }
        else
        {
            ss << str[i++];
        }
    }
}

//**************************申明并定义Mylog类***************************//
class Mylog
{
public:
    template <typename... Args>
    void error(const char *msg, Args... args);
    template <typename... Args>
    void warn(const char *msg, Args... args);
    template <typename... Args>
    void debug(const char *msg, Args... args);
    template <typename... Args>
    void info(const char *msg, Args... args);
    static Mylog *getInstance();
    static void destory();

private:
    Mylog();
    ~Mylog();

private:
    static Mylog *_pInstance;
    Category &_root;
};

Mylog *Mylog::getInstance()
{
    if (!_pInstance)
    {
        _pInstance = new Mylog();
    }
    return _pInstance;
}

Mylog::Mylog()
    : _root(Category::getRoot().getInstance("rootCategory"))
{
    OstreamAppender *Osappender = new OstreamAppender("Osappender", &cout);
    PatternLayout *layout1 = new PatternLayout();
    layout1->setConversionPattern("%d: [%p] %m %n");
    Osappender->setLayout(layout1);
    _root.addAppender(Osappender);
    _root.setPriority(Priority::DEBUG);
    _root.info("Mylog()");
}

Mylog::~Mylog()
{
    _root.info("~Mylog()");
}

void Mylog::destory()
{
    if (_pInstance)
    {
        delete _pInstance;
        _pInstance = NULL;
    }
    Category::shutdown();
}

template <typename... Args>
void Mylog::warn(const char *msg, Args... args)
{
    stringstream ss;
    stringstream temp;
    Myprintf(temp, msg, args...);
    ss << "\"" << temp.str() << "\"" << setw(10) << "FileName:" << __FILE__ << setw(10) << " Function():" << __FUNCTION__ << setw(10) << " LINE:" << __LINE__;
    _root.warn(ss.str());
}

template <typename... Args>
void Mylog::info(const char *msg, Args... args)
{
    stringstream ss;
    stringstream temp;
    Myprintf(temp, msg, args...);
    ss << "\"" << temp.str() << "\"" << setw(10) << "FileName:" << __FILE__ << setw(10) << " Function():" << __FUNCTION__ << setw(10) << " LINE:" << __LINE__;
    _root.info(ss.str());
}

template <typename... Args>
void Mylog::debug(const char *msg, Args... args)
{
    stringstream ss;
    stringstream temp;
    Myprintf(temp, msg, args...);
    ss << "\"" << temp.str() << "\"" << setw(10) << "FileName:" << __FILE__ << setw(10) << " Function():" << __FUNCTION__ << setw(10) << " LINE:" << __LINE__;
    _root.debug(ss.str());
}

template <typename... Args>
void Mylog::error(const char *msg, Args... args)
{
    stringstream ss;
    stringstream temp;
    Myprintf(temp, msg, args...);
    ss << "\"" << temp.str() << "\"" << setw(10) << "FileName:" << __FILE__ << setw(10) << " Function():" << __FUNCTION__ << setw(10) << " LINE:" << __LINE__;
    _root.error(ss.str());
}

//*************下面将Mylog中的函数直接定义为内联函数,可以直接调用**************//
Mylog *Mylog::_pInstance = NULL;
Mylog *log = Mylog::getInstance();

template <typename... Args>
inline void LogError(const char *msg, Args... args)
{
    log->error(msg, args...);
}

template <typename... Args>
inline void LogWarn(const char *msg, Args... args)
{
    log->warn(msg, args...);
}

template <typename... Args>
inline void LogInfo(const char *msg, Args... args)
{
    log->info(msg, args...);
}

template <typename... Args>
inline void LogDebug(const char *msg, Args... args)
{
    log->debug(msg, args...);
}

} // namespace wd

#endif

main.cpp:

#include "Mylog.h"
using namespace wd;


int main(){
    LogError("Hello%d %d %c %s", 1,2,'3', "456");
    LogWarn("wan");
    LogInfo("info");
    LogDebug("debug");
    return 0;
}

output:

wwx@linux:~/week3/homework_mylog$ g++ main.cpp -llog4cpp -lpthread
wwx@linux:~/week3/homework_mylog$ ./a.out
2020-03-08 22:29:00,215: [INFO] Mylog() 
2020-03-08 22:29:00,216: [ERROR] "Hello1 2 3 456" FileName:Mylog.h Function():error     LINE:159 
2020-03-08 22:29:00,216: [WARN] "wan" FileName:Mylog.h Function():warn     LINE:129 
2020-03-08 22:29:00,216: [INFO] "info" FileName:Mylog.h Function():info     LINE:139 
2020-03-08 22:29:00,216: [DEBUG] "debug" FileName:Mylog.h Function():debug     LINE:149 
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值