今天主要讲了C++的log4cpp库
概述
Log4cpp是个基于LGPL的开源项目,移植自Java的日志处理跟踪项目log4j,并保持了API上的一致。其类似的支持库还包括Java(log4j),C++(log4cpp、log4cplus),C(log4c),python(log4p)等。(摘自百度百科)
简言之,log4cpp可以理解为一个日志管理系统。
主要部件
- 记录器 Category
- 过滤器 日志优先级,详情见下文
- 格式化器 Layout
- 输出器 Appender:OstreamAppender,FileAppender,RollingAppender
Priority
结构体定义如下,其中数值越小,表示优先级越高,当日志信息的优先级高于设定的优先级时,该条信息才会被处理,否则丢弃
typedef enum {EMERG = 0,
FATAL = 0,
ALERT = 100,
CRIT = 200,
ERROR = 300,
WARN = 400,
NOTICE = 500,
INFO = 600,
DEBUG = 700,
NOTSET = 800
} PriorityLevel;
Category
可使用Category::getRoot()得到根Category,一般情况下,一个程序只需一个根Category,负责向日志中写入信息
Appender
负责制定日志的目的地,以下代码分别把日志信息写入到标准输出cout和文件tmp_log.txt中
OstreamAppender *ostreamAppender = new OstreamAppender("ostreamAppender", &cout);
FileAppender *fileAppender = new FileAppender("fileAppender", "tmp_log.txt");
PatternLayout
创建一个PatternLayout后,可以使用setConversionPattern方法来设置日志的输出格式,以下摘录自官方手册 log4cpp Documentation
Format characters are as follows:
%%%% - a single percent sign
%c - the category
%d - the date
Date format: The date format character may be followed by a date format specifier enclosed between braces. For example, %d{%H:%M:%S,%l} or %d{%d %m %Y %H:%M:%S,%l}. If no date format specifier is given then the following format is used: "Wed Jan 02 02:03:55 1980". The date format specifier admits the same syntax as the ANSI C function strftime, with 1 addition. The addition is the specifier %l for milliseconds, padded with zeros to make 3 digits.
%m - the message
%n - the platform specific line separator
%p - the priority
%r - milliseconds since this layout was created.
%R - seconds since Jan 1, 1970
%u - clock ticks since process start
%x - the NDC
下述代码即可设置日志输出格式为:日期 category [优先级] 消息 换行符
PatternLayout *p1 = new PatternLayout();
p1->setConversionPattern("%d %c [%p] %m%n");
运行
log->error("this is a error");
结果
2019-07-27 23:13:33,412 [ERROR] this is a error
shutdown()
使用完毕后最好使用Category::shutdown()进行内存清理,但即使不手动调用,程序结束时也会自动调用Category的析构函数进行清理。
自己封装的log4cpp类
#include <log4cpp/Category.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/Priority.hh>
#include <log4cpp/Appender.hh>
#include <iostream>
#include <string>
using namespace std;
using namespace log4cpp;
/* • __LINE__:在源代码中插入当前源代码行号
• __FILE__:在源文件中插入当前源文件名
• __FUNCTION__:函数名
• __DATE__:在源文件中插入当前的编译日期
• __TIME__:在源文件中插入当前编译时间 */
//定义一个宏,以输出日志信息所在的文件名,函数名和所在行
#define getinfo(msg) (string(msg).append(" [").append(__FILE__).append(" ").\
append(__FUNCTION__).append(":").append(to_string(__LINE__)).append("]")).c_str()
class Mylogger
{
public:
static Mylogger *getstance()
{
if (_pinstance == nullptr)
_pinstance = new Mylogger();
return _pinstance;
}
void destory()
{
if (_pinstance)
delete _pinstance;
_pinstance = nullptr;
}
void warn(const char *msg);
void error(const char *msg);
void debug(const char *msg);
void info(const char *msg);
private:
Mylogger();
~Mylogger();
PatternLayout *_p1;
PatternLayout *_p2;
OstreamAppender *_ostreamAppender;
FileAppender *_fileAppender;
Category &_root;
static Mylogger *_pinstance;
};
Mylogger* Mylogger::_pinstance = nullptr;
Mylogger::Mylogger()
: _p1(new PatternLayout())
, _p2(new PatternLayout())
, _ostreamAppender(new OstreamAppender("ostreamAppender", &cout))
, _fileAppender(new FileAppender("fileAppender", "log.txt"))
, _root(Category::getRoot())
{
_p1->setConversionPattern("%d %c [%p] %m%n");
_p2->setConversionPattern("%d %c [%p] %m%n");
_ostreamAppender->setLayout(_p1);
_fileAppender->setLayout(_p2);
cout << "nihao" << endl;
_root.setPriority(Priority::DEBUG);
_root.addAppender(_ostreamAppender);
_root.addAppender(_fileAppender);
//Category::shutdown();
}
Mylogger::~Mylogger()
{
Category::shutdown();
cout << "析构函数" << endl;
}
void Mylogger::warn(const char *msg)
{
_root.warn(msg);
}
void Mylogger::error(const char *msg)
{
_root.error(msg);
}
void Mylogger::debug(const char *msg)
{
_root.debug(msg);
}
void Mylogger::info(const char *msg)
{
_root.info(msg);
}
int main(int argc, char *argv[])
{
Mylogger *p = Mylogger::getstance();
p->warn(getinfo("warn"));
p->error(getinfo("error"));
p->debug(getinfo("debug"));
p->info(getinfo("info"));
p->destory();
return 0;
}