log4cpp日志系统

服务器的模块中,日志系统是必不可少的

服务器的程序特点: 没有终端 守护进程 7 * 24小时

如何去设计一个日志系统?

一条日志的产生,到最终被保存下来的全过程

日志来源:一个服务器的程序是有多个模块,需要知道一条日志由哪一个模块产生的

日志布局: 对一条日志的格式进行控制

日志过滤器: 不同的用户看到不同类型的日志信息 通过日志的优先级

日志目的地: 终端、文件、远程服务器

日志分类

  1. 系统日志
  2. 业务日志

已经有的日志系统

img

log4cpp

1. 安装
$ tar xzvf log4cpp-1.1.4rc3.tar.gz
$ cd log4cpp
$ ./configure
$ make
$ sudo make install
$ sudo ldconfig

img

2.安装后验证是否安装成功

img

测试程序

#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";

    return 0;
}

img

找不到动态库

img

img

成功:

img

Category

日志来源: Category 日志是由Category对象产生的

每一次记录一条日志是由其成员函数进行的,表示该条日志的优先级是debug/info/…

img

Category对象是可以设置自己的优先级,img

每一条日志也有自己的优先级

当每一条日志的优先级大于等于Category的优先级时,该条日志才会被记录

设置多个目的地:

img

Category具有层级概念

root设置的优先级会被子Category继承

img

Priority

img

优先级的值越小的,优先级别越高

值越大的,优先级别越低

参考: Linux 环境下 syslog函数

img

Layout

img

void setConversionPattern(const std::string & conversionPattern)

img

patternLayout 支持以下格式字符集:

%%-单个百分号

%c - 类别

%d - 日期\n 日期格式:日期格式字符可以用于

例如,%d{%h:%m:%s,%l} 或 %d{%d %m %y 7%y %h:

使用以下格式:“Wed Jan 02 02:03:55 1980”.the date forn

function strftime 的函数,增加了 1 个。添加的是

%m 消息

%n 特定于平台的行分隔符

%p 优先级

%r - 自创建此布局以来的毫秒数。

%R - 自 1970 年 1 月 1 日以来的秒数

%u-自 PE 进程启动以来的 clock 时钟周期

%x - NDC

%t 线程名称

默认情况下,patternLayout 的 conversionPattern 设置为 “%m%n”。

#include<iostream>

#include<log4cpp/Category.hh>
#include<log4cpp/OstreamAppender.hh>
#include<log4cpp/FileAppender.hh>
#include<log4cpp/Priority.hh>
#include<log4cpp/PatternLayout.hh>

using std::cout;
using std::endl;

using namespace log4cpp;

void test0()
{
    PatternLayout * ptnLayout=new PatternLayout();
    ptnLayout->setConversionPattern("%d %c [%p] %m%n");
    
    PatternLayout * ptnLayout2=new PatternLayout();                                                                            
    ptnLayout2->setConversionPattern("%d %c [%p] %m%n");

    OstreamAppender * pOsApp=new OstreamAppender("console",&cout);
    pOsApp->setLayout(ptnLayout);

    FileAppender * pFileApp=new FileAppender("fileApp","wd.log");
    pFileApp->setLayout(ptnLayout2);

    Category & mycat=Category::getRoot().getInstance("salesDapart");
    mycat.setPriority(Priority::DEBUG);
    mycat.addAppender(pOsApp);
    mycat.addAppender(pFileApp);

    mycat.emerg("this is an emerg message");
    mycat.fatal("this is a fatal message");
    mycat.alert("this is an alert message");
    mycat.crit("this is a crit message");
    mycat.error("this is an error message");
    mycat.warn("this an error message");
    mycat.info("this is an info message");
    mycat.notice("this is a notice message");
    mycat.debug("this a debug message");

    Category::shutdown();
}

int main()
{
    test0();
}
g++ log4cpptest.cc -llog4cpp -lpthread//顺序不能反,不然会编译出错

img

Appender

img

一个目的地对应一个日志布局

void setLayout (Layout *layout)//一个目的地对应一个日志布局
OstreamAppender (const std::string &name, std::ostream *stream)
FileAppender (const std::string &name, const std::string &fileName, bool append=true, mode_t mode=00644)//append:以追加方式写入文件
bug

img

img

回卷文件

目的: 节省空间

 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)
//name:文件的名字	//maxFileSize:一个文件的最大字节数	//maxBackupIndex:回卷的文件数

img

img

比如一个服务器设定系统日志文件占据的空间的就限定为1G,1个日志文件最多只能占据的空间是100M,日志文件就有10个,当10个文件填满之后,最新的数据用来覆盖最旧的数据

#include<iostream>

#include<log4cpp/Category.hh>
#include<log4cpp/OstreamAppender.hh>
#include<log4cpp/FileAppender.hh>
#include<log4cpp/RollingFileAppender.hh>
#include<log4cpp/Priority.hh>
#include<log4cpp/PatternLayout.hh>

using std::cout;
using std::endl;

using namespace log4cpp;

void test0()
{
    PatternLayout * ptnLayout=new PatternLayout();
    ptnLayout->setConversionPattern("%d %c [%p] %m%n");
    
    PatternLayout * ptnLayout2=new PatternLayout();                                                                            
    ptnLayout2->setConversionPattern("%d %c [%p] %m%n");

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

    OstreamAppender * pOsApp=new OstreamAppender("console",&cout);
    pOsApp->setLayout(ptnLayout);

    FileAppender * pFileApp=new FileAppender("fileApp","wd.log");
    pFileApp->setLayout(ptnLayout2);

    auto pRollingFileApp=new RollingFileAppender("rollingfileApp","rollingwd.log",5*1024,3);
    pRollingFileApp->setLayout(ptnLayout3);

    Category & mycat=Category::getRoot().getInstance("salesDapart");
    mycat.setPriority(Priority::DEBUG);
    mycat.addAppender(pOsApp);
    mycat.addAppender(pFileApp);
    mycat.addAppender(pRollingFileApp);

    for(int i=0;i<100;++i){
        mycat.emerg("this is an emerg message");
        mycat.fatal("this is a fatal message");
        mycat.alert("this is an alert message");
        mycat.crit("this is a crit message");
        mycat.error("this is an error message");
        mycat.warn("this an error message");
        mycat.info("this is an info message");
        mycat.notice("this is a notice message");
        mycat.debug("this a debug message");
    }
    Category::shutdown();
}

int main()
{
    test0();
}

尝试将 优先级等 写入配置文件,使得修改优先级不需要修改源码:

# log4cpp.properties

log4cpp.rootCategory=DEBUG, rootAppender
log4cpp.category.sub1=DEBUG, A1, A2
log4cpp.category.sub1.sub2=DEBUG, A3

log4cpp.appender.rootAppender=ConsoleAppender
log4cpp.appender.rootAppender.layout=PatternLayout
log4cpp.appender.rootAppender.layout.ConversionPattern=%d [%p] %m%n 

log4cpp.appender.A1=FileAppender
log4cpp.appender.A1.fileName=A1.log
log4cpp.appender.A1.layout=BasicLayout

log4cpp.appender.A2=FileAppender
log4cpp.appender.A2.threshold=WARN
log4cpp.appender.A2.fileName=A2.log
log4cpp.appender.A2.layout=PatternLayout
log4cpp.appender.A2.layout.ConversionPattern=%d [%p] %m%n 

log4cpp.appender.A3=RollingFileAppender
log4cpp.appender.A3.fileName=A3.log
log4cpp.appender.A3.maxFileSize=200
log4cpp.appender.A3.maxBackupIndex=1
log4cpp.appender.A3.layout=PatternLayout
log4cpp.appender.A3.layout.ConversionPattern=%d [%p] %m%n 
#include <log4cpp/Category.hh>
#include <log4cpp/PropertyConfigurator.hh>

int main(int argc, char* argv[])
{
	std::string initFileName = "log4cpp.conf";
	log4cpp::PropertyConfigurator::configure(initFileName);

	log4cpp::Category& root = log4cpp::Category::getRoot();

	log4cpp::Category& sub1 = 
		log4cpp::Category::getInstance(std::string("sub1"));

	log4cpp::Category& sub2 = 
		log4cpp::Category::getInstance(std::string("sub1.sub2"));

	root.warn("Storm is coming");

	sub1.debug("Received storm warning");
	sub1.info("Closing all hatches");

	sub2.debug("Hiding solar panels");
	sub2.error("Solar panels are blocked");
	sub2.debug("Applying protective shield");
	sub2.warn("Unfolding protective shield");
	sub2.info("Solar panels are shielded");

	sub1.info("All hatches closed");

	root.info("Ready for storm.");

	log4cpp::Category::shutdown();

	return 0;
}

封装 log4cpp:

#ifndef __WD_Mylogger_HPP__//如果没有定义一个宏,就会定义一个宏
#define __WD_Mylogger_HPP__//在同一个*.cc文件中加载多次时,不会报重复定义的错误
//预处理操作是针对于一个*.cc文件的,当头文件在一个*.cc文件出现多次时,只有一份Mylogger源码出现
//keep ypur code clean
#include<log4cpp/Category.hh>
using std::string;
namespace wd
{
class Mylogger
{
public:
    static Mylogger *getInstance();//2.定义了一个静态的成员函数用来初始化
    static void destroy();

    void error(const char *msg);
    void warn(const char *msg);
    void info(const char *msg);
    void debug(const char *msg);
private:
    Mylogger();//1、构造函数私有化
    ~Mylogger();

private:
    log4cpp::Category & _mycat;
    //log4cpp::OstreamAppender * _pos;
    static Mylogger * _pInstance;3、定义一个静态的能够存储本类型对象的指针
};


#define addprefix(msg) string ("[").append(__FILE__).append(":")\
        .append(__FUNCTION__).append(":")\
        .append(std::to_string(__LINE__))\
        .append("]").append(msg).c_str()

#define LogError(msg) wd::Mylogger::getInstance()->error(addprefix(msg))
#define LogWarn(msg) wd::Mylogger::getInstance()->warn(addprefix(msg))
#define LogInfo(msg) wd::Mylogger::getInstance()->info(addprefix(msg))
#define LogDebug(msg) wd::Mylogger::getInstance()->debug(addprefix(msg))
}//end of namespace wd_
#endif//之前的代码都会衔接到被引用的文件中
#include"Mylogger.hpp"
#include<log4cpp/Priority.hh>
#include<log4cpp/OstreamAppender.hh>
#include<log4cpp/FileAppender.hh>
#include<log4cpp/PatternLayout.hh>
#include<iostream>

using std::cout;
using std::endl;
using namespace log4cpp;
namespace wd
{
Mylogger * Mylogger::_pInstance=nullptr;

Mylogger * Mylogger:: getInstance()
{
    if(_pInstance==nullptr){
        _pInstance=new Mylogger();
    }
    return _pInstance;
}

void Mylogger::destroy()
{
    if(_pInstance){
        delete _pInstance;
        _pInstance=nullptr;//safe delete
    }
}

Mylogger::Mylogger()
:_mycat(Category::getRoot().getInstance("mycat"))//这里的getRoot是为了强调层级概念
{
    //C++11新特性
    auto ptnLayout1=new PatternLayout();
    ptnLayout1->setConversionPattern("%d %c [%p] %m%n");
    auto ptnLayout2=new PatternLayout();
    ptnLayout2->setConversionPattern("%d%c [%p] %m%n");
    auto posApp=new OstreamAppender("console",&cout);
    posApp->setLayout(ptnLayout1);
    auto pfileApp=new FileAppender("pfileApp","wd.log");
    pfileApp->setLayout(ptnLayout2);

    _mycat.setPriority(Priority::DEBUG);
    _mycat.addAppender(posApp);
    _mycat.addAppender(pfileApp);
    cout<<"Mylogger()"<<endl;

}


Mylogger::~Mylogger()
{
    Category::shutdown();
    cout<<"~Mylogger()"<<endl;
}
void Mylogger::error(const char * msg)
{   _mycat.error(msg);}
void Mylogger::warn(const char * msg)
{   _mycat.warn(msg);}
void Mylogger::info(const char * msg)
{   _mycat.info(msg);}
void Mylogger::debug(const char * msg)
{   _mycat.debug(msg);}
}//end of namespace
#include"Mylogger.hpp"
#include<iostream>
//#include<string.h>
using std::cout;
using std::endl;
using std::string;

void test0()
{
    wd::Mylogger::getInstance()->error("this is an error msg");
    wd::Mylogger::getInstance()->warn("this is an warn msg");
    wd::Mylogger::getInstance()->info("this is an info msg");
    wd::Mylogger::getInstance()->debug("this is an debug msg");

}

void test1()
{
    cout<<__FILE__<<endl;//宏在预编译时会替换成当前的源文件名
    cout<<__LINE__<<endl;//宏在预编译时会替换成当前的行号
    cout<<__FUNCTION__<<endl;//宏在预编译时会替换成当前的函数名称
    cout<<__func__<<endl;
}

void test2()
{
    cout<<addprefix("this is a test msg")<<endl;
    cout<<addprefix("this is a test2 msg")<<endl;
}
void test3()
{

    wd::Mylogger::getInstance()->error(addprefix("this is an error msg"));
    wd::Mylogger::getInstance()->warn(addprefix("this is a warn msg"));
    wd::Mylogger::getInstance()->info(addprefix("this is an info msg"));
    wd::Mylogger::getInstance()->debug(addprefix("this is a debug msg"));
}
void test4()
{
    LogError("this is an error message");//%d
    LogWarn("this is a warn message");
    LogInfo("this is an info message");
    LogDebug("this is a debug message");
}
int main()
{
    //test0();
    //wd::Mylogger::destroy();
    //test1();
    //test2();
    test4();
    wd::Mylogger::destroy();
    return 0;
}

img

遇到的 bug:

img

Mylogger * Mylogger::_pInstance=nullptr;放头文件,被多个文件引用

g++ *.cc -llog4cpp -lpthread

log4cpp-1.1.5rc1.tar.gz

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值