Log4cpp使
Log4cpp中最重要概念有Category(种类)、Appender(附加器)、Layout(布局)、Priorty(优先 级)、NDC(嵌套的诊断上下)。
Category、Appender与Layout三者的关系如下图所示:
下载地址:https://sourceforge.net/projects/log4cpp/files/latest/download 我下载的是: log4cpp-1.1.3.tar.gz
解压:
tar zxf log4cpp-1.1.3.tar.gz 编译:
cd log4cpp
./configure
make
make check
sudo make install
RollingFileAppender.cpp
/*
FileAppender和RollingFileAppender是log4cpp中最常用的两个Appender,其功能是将日志写入文件中。
它们之间唯一的区别就是前者会一直在文件中记录日志(直到操作系统承受不了为止),而后者会在文件长度到
达指定值时循环记录日志,文件长度不会超过指定值(默认的指定值是10M byte)。
FileAppender的创建函数如下:
FileAppender(const std::string& name, const std::string& fileName,
bool append = true, mode_t mode = 00644);
一般仅使用前两个参数,即“名称”和“日志文件名”。第三个参数指示是否在日志文件后继续记入日志,
还是清空原日志文件再记录。第四个参数说明文件的打开方式。
RollingFileAppender的创建函数如下:
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);
它与FileAppender的创建函数很类似,但是多了两个参数:maxFileSize指出了回滚文件的最大值;
maxBackupIndex指出了回滚文件所用的备份文件的最大个数。所谓备份文件,是用来保存回滚文件中
因为空间不足未能记录的日志,备份文件的大小仅比回滚文件的最大值大1kb。所以如果maxBackupIndex取值为3,
则回滚文件(假设其名称是rollwxb.log,大小为100kb)会有三个备份文件,
其名称分别是rollwxb.log.1,rollwxb.log.2和rollwxb.log.3,大小为101kb。
另外要注意:如果maxBackupIndex取值为0或者小于0,则回滚文件功能会失效,其表现如同FileAppender一样,
不会有大小的限制。
*/
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
static uint64_t get_tick_count()
{
struct timeval tval;
uint64_t ret_tick;
gettimeofday(&tval, NULL);
ret_tick = tval.tv_sec * 1000L + tval.tv_usec / 1000L;
return ret_tick;
}
// g++ -o RollingFileAppender RollingFileAppender.cpp -llog4cpp -lpthread
int main(int argc, char* argv[])
{
log4cpp::TimeStamp time;
log4cpp::PatternLayout* pLayout1 = new log4cpp::PatternLayout();
log4cpp::BasicLayout* pBasicLayout = new log4cpp::BasicLayout();
// 2020-06-21 17:36:01,946: ERROR RootName : 0:Root Error Message!
// %d: 2020-06-21 17:36:01,946:
// %p ERROR
// %c RootName : 0
// %m:Root Error Message!
// pLayout1->setConversionPattern("%d: %p %c %x: %m%n");
// 2020-06-21 17:40:34,772: ERROR RootName: 10Root Error Message!
// pLayout1->setConversionPattern("%d: %p %c: %m%n");
// 2020-06-21 17:41:41,369: ERROR : 0Root Error Message!
pLayout1->setConversionPattern("%d: %p %c %x: %m%n");
log4cpp::PatternLayout* pLayout2 = new log4cpp::PatternLayout();
pLayout2->setConversionPattern("%d: %p %c %x: %m%n");
log4cpp::Appender* fileAppender = new log4cpp::FileAppender("fileAppender","FileAppender.log",
false);
fileAppender->setLayout(pLayout1);
log4cpp::RollingFileAppender* rollfileAppender = new log4cpp::RollingFileAppender(
"rollfileAppender","RollingFileAppender.log",500*1024,5, false);
rollfileAppender->setLayout(pLayout2);
log4cpp::Category& root = log4cpp::Category::getRoot().getInstance("RootName");
// root.addAppender(fileAppender);
root.addAppender(rollfileAppender);
root.setPriority(log4cpp::Priority::DEBUG);
uint64_t begin_time = get_tick_count();
std::cout << "begin_time: " << begin_time << std::endl;
for (int i = 0; i < 10000; i++)
{
string strError;
ostringstream oss;
oss<<"NO." << i<<" Root Error Message!"; // 47个字节
strError = oss.str();
root.error(strError);
}
uint64_t end_time = get_tick_count();
std::cout << "end_time: " << end_time << std::endl;
std::cout << "need the time1: " << end_time << " " << begin_time << ", " << end_time - begin_time << "毫秒\n" ;
log4cpp::Category::shutdown();
end_time = get_tick_count();
std::cout << "need the time2: " << end_time - begin_time << "毫秒\n" ;
return 0;
}
StringQueueAppender.CPP
/*
StringQueueAppender的功能是将日志记录到一个字符串队列中,该字符串队列使用了STL中的两个容器,
即字符串容器std::string和队列容器std::queue,具体如下:
std::queue _queue;
_queue变量是StringQueueAppender类中用于具体存储日志的内存队列。StringQueueAppender的使用方法
与OstreamAppender类似,其创建函数只接收一个参数“名称”,记录完成后需要程序员自己从队列中取出每条日志
*/
#include
#include
#include
#include
#include
#include
#include
using namespace std;
static uint64_t get_tick_count()
{
struct timeval tval;
uint64_t ret_tick;
gettimeofday(&tval, NULL);
ret_tick = tval.tv_sec * 1000L + tval.tv_usec / 1000L;
return ret_tick;
}
// g++ -o StringQueueAppender StringQueueAppender.cpp -llog4cpp -lpthread
int main(int argc, char* argv[])
{
log4cpp::StringQueueAppender* strQAppender = new log4cpp::StringQueueAppender("strQAppender");
strQAppender->setLayout(new log4cpp::BasicLayout());
log4cpp::Category& root = log4cpp::Category::getRoot();
root.addAppender(strQAppender);
root.setPriority(log4cpp::Priority::DEBUG);
root.error("Hello log4cpp in a Error Message!");
root.warn("Hello log4cpp in a Warning Message!");
cout<<"Get message from Memory Queue!"<& myStrQ = strQAppender->getQueue();
std::string bufString;
int bufCount = 0;
begin_time = get_tick_count();
std::cout << "begin_time: " << begin_time << std::endl;
FILE *file = fopen("StringQueueAppender.log", "wt");
while(!myStrQ.empty())
{
// cout<= 100000)
{
bufCount = 0;
// std::cout << myStrQ.front() << std::endl;
fwrite(bufString.c_str(), bufString.size(), 1, file);
bufString.clear();
}
myStrQ.pop();
}
fwrite(bufString.c_str(), bufString.size(), 1, file);
fclose(file);
end_time = get_tick_count();
std::cout << "need the time1: " << end_time << " " << begin_time << ", " << end_time - begin_time << "毫秒\n" ;
log4cpp::Category::shutdown();
return 0;
}
test_log4cpp1.CPP
// FileName: test_log4cpp1.cpp
#include "log4cpp/Category.hh"
#include "log4cpp/FileAppender.hh"
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/BasicLayout.hh"
//g++ -o test_log4cpp1 test_log4cpp1.cpp -llog4cpp -lpthread
int main(int argc, char *argv[])
{
// 1实例化一个layout 对象
log4cpp::Layout *layout = new log4cpp::BasicLayout(); // 有不同的layout
// 2. 初始化一个appender 对象
log4cpp::Appender *appender = new log4cpp::FileAppender("FileAppender",
"./test_log4cpp1.log");
log4cpp::Appender *osappender = new log4cpp::OstreamAppender("OstreamAppender",
&std::cout);
// 3. 把layout对象附着在appender对象上
appender->setLayout(layout);
// appender->addLayout 没有addLayout,一个layout格式样式对应一个appender
// 4. 实例化一个category对象
log4cpp::Category &warn_log =
log4cpp::Category::getInstance("darren"); // 是一个单例工厂
// 5. 设置additivity为false,替换已有的appender
warn_log.setAdditivity(false);
// 5. 把appender对象附到category上
warn_log.setAppender(appender);
warn_log.addAppender(osappender);
// 6. 设置category的优先级,低于此优先级的日志不被记录
warn_log.setPriority(log4cpp::Priority::INFO);
// 记录一些日志
warn_log.info("Program info which cannot be wirten, darren = %d", 100);
warn_log.debug("This debug message will fail to write");
warn_log.alert("Alert info");
// 其他记录日志方式
warn_log.log(log4cpp::Priority::WARN, "This will be a logged warning, darren = %d", 100);
log4cpp::Priority::PriorityLevel priority;
bool this_is_critical = true;
if (this_is_critical)
priority = log4cpp::Priority::CRIT;
else
priority = log4cpp::Priority::DEBUG;
warn_log.log(priority, "Importance depends on context");
warn_log.critStream() << "This will show up << as "
<< 1 << " critical message";
// clean up and flush all appenders
log4cpp::Category::shutdown();
return 0;
}
才配置文件形式来写日志文件
test_log4cpp2.conf
# 文件名: test_log4cpp2.conf
# a simple test config
#定义了3个category sub1, sub2, sub1.sub2
log4j.rootCategory=DEBUG, rootAppender
log4j.category.sub1=,A1
log4j.category.sub2=INFO
#log4j.category.sub1.sub2=ERROR, A2
log4j.category.sub1.sub2=, A2
# 设置sub1.sub2 的additivity属性
log4j.additivity.sub1.sub2=true
#定义rootAppender类型和layout属性
log4j.appender.rootAppender=org.apache.log4j.ConsoleAppender
log4j.appender.rootAppender.layout=org.apache.log4j.BasicLayout
#定义A1的属性
log4j.appender.A1=org.apache.log4j.FileAppender
log4j.appender.A1.fileName=A1.log
log4j.appender.A1.layout=org.apache.log4j.SimpleLayout
#定义A2的属性
log4j.appender.A2=org.apache.log4j.ConsoleAppender
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
#log4j.appender.A2.layout.ConversionPattern=The message '%m' at time %d%n
log4j.appender.A2.layout.ConversionPattern=%d %m %n
test_log4cpp2.cpp
// FileName: test_log4cpp2.cpp
// Test log4cpp by config file.
#include "log4cpp/Category.hh"
#include "log4cpp/PropertyConfigurator.hh"
//g++ -o test_log4cpp2 test_log4cpp2.cpp -llog4cpp -lpthread
int main(int argc, char* argv[])
{
// 1 读取解析配置文件
// 读取出错, 完全可以忽略,可以定义一个缺省策略或者使用系统缺省策略
// BasicLayout输出所有优先级日志到ConsoleAppender
try {
log4cpp::PropertyConfigurator::configure("./test_log4cpp2.conf");
} catch(log4cpp::ConfigureFailure& f) {
std::cout << "Configure Problem " << f.what() << std::endl;
return -1;
}
// 2 实例化category对象
// 这些对象即使配置文件没有定义也可以使用,不过其属性继承其父category
// 通常使用引用可能不太方便,可以使用指针,以后做指针使用
// log4cpp::Category* root = &log4cpp::Category::getRoot();
log4cpp::Category& root = log4cpp::Category::getRoot();
log4cpp::Category& sub1 =
log4cpp::Category::getInstance(std::string("sub1"));
log4cpp::Category& sub3 =
log4cpp::Category::getInstance(std::string("sub1.sub2"));
// 3 正常使用这些category对象进行日志处理。
// sub1 has appender A1 and rootappender.
sub1.info("This is some info");
sub1.alert("A warning");
// sub3 only have A2 appender.
sub3.debug("This debug message will fail to write");
sub3.alert("All hands abandon ship");
sub3.critStream() << "This will show up << as " << 1 << " critical message";
sub3 << log4cpp::Priority::ERROR
<< "And this will be an error";
sub3.log(log4cpp::Priority::WARN, "This will be a logged warning");
// clean up and flush all appenders
log4cpp::Category::shutdown();
return 0;
}