Logcpp/Logc++ 用法详解
Logcplusplus(使用上常被称作Logc++)。它的存在简化了在C++应用程序中建立日志和跟踪处理。当你的程序超过500行,或者运行一个后台程序或服务时,如果你不想因为调试程序而绞尽脑汁的话,或是当你需要回到一个月前的某个状态,那你就使用跟踪。
那么C++应用程序是如果跟踪的呢。
如果你使用的是面向过程的语言,比如C,你可能还需要使用以前的:
<listing>
#ifdef DEBUG
fprintf(trace_file,"Here is a useless trace message!/n");
#endif
</listing>
但如果你现在使用的是面向对象的语言,随机的输出信息到一个跟踪文件上就显得不那么优雅了,这时你需要一个跟踪和记录日志的类。
Ceki Gulcu创建了一个在JAVA中叫做log4j的功能强大的日志和跟踪对象集。Bastiaan Bakker 则在C++中实现了大部分类似的集并且称他为log4cpp。都是开源的,你可以在http://sourceforge.net或其它地方免费获得。
插入日志,跟踪代码并不是什么高科技,但是它非常有效。如果正确的使用它,它甚至可以构成软件审核的基础,或者成为一个高效的错误日志检测工具。日志会降低程序的运行速度,但是log4j和log4cpp的创作者们已经尽可能的减少了会导致降低程序运行速度的环节。
所以如果你对记录日志和追踪饶有兴致而且希望使用一个杰出并且免费而且可用的工具,那就接着往下看吧!
loc4cpp有三个重要组成部分:category ,appender ,layout。
layout类控制输出信息的格式和样式。你可以使你的类基于layout,来指定你想要的输出数据的风格。log4cpp自带两个layout类。分别是SimpleLayout和BasicLayout。
appender类用来输出信息到设备上。这些信息已经被layout对象格式化过了。设备可以是标准输出,一个文件或者一个string buffer。你可以得到你自己的appender类如果你想要在一个socket,共享内存缓冲区或者其他一些写延迟设备。loc4cpp自带了3个非常有用的appender类。分别是FileAppender,OstreamAppender,和StringQueueAppender。
category类。appender 和它的优先级是category的重要组成部分。优先级控制那些可以被特定类记录的日志消息。当category对象被创建时,它会构造一个默认的标准输出的appender,和一个默认的优先级。可以在记录日志的目标列表中添加更多的appender。可以通过NOTSET,DEBUG,INFO,NOTICE,WARN,ERROR,CRIT,ALERT或者FATAL/EMERG,按照递增顺序或者重要等级来设置日志信息。每条信息都被记录到category对象。而消息本身也有一个优先级。如果消息的优先级更高或者与category的优先级相同,记录日志就会发生,否
则这条消息会被忽略。category的优先级顺序如下:
<listing>
NOTSET < DEBUG < INFO < NOTICE < WARN < ERROR < CRIT < ALERT < FATAL = EMERG
</listing>
所以根据这种策略
-如果category对象设置了NOTSET优先级,它会接受并记录任何消息到日志中。因为消息可以被设置成以上除了NOTSET的任何优先级别。
-如果category对象设置了WARN,任何DEBUG,INFO,NOTICE优先级的消息都会被忽略掉。
appender作为一个累加对象被添加到category中。当appender被加到category,默认的操作是添加appender到为了记录日志消息的目标列表中。它有可能同时记录日志或者追踪到两个文件作为回应标准输出。
在实践中,你很少会希望同时在多个地方记录日志,而这个你希望的目标永远不可能是标准输出。log4cpp允许你用additivity标志。如果additivity被设置成false,当一个新的appender被关联到category对象时,它将不会添加到目标列表,它代替了category对象中的当前appender列表。
介绍了这三个类,那么这些是怎么联系的呢。category类创建一个全局的静态根category类(root)。应用程序可以从这个静态父类创建子类的实例。
接下来我们看一个简单的例子。
1.初始化一个appender对象
2.初始化一个layout对象
3.将layout关联到appender对象
4.调用静态函数初始化一个category类
5.将appender对象作为添加对象关联到category类
<listing>
// TestLog4CPP.cpp : A small exerciser for log4cpp
#include "Category.hh"
#include "FileAppender.hh"
#include "BasicLayout.hh"
int main(int argc, char* argv[])
{
// 1 instantiate an appender object that
// will append to a log file
log4cpp::Appender* app = new
log4cpp::FileAppender("FileAppender",
"/logs/testlog4cpp.log");
// 2. Instantiate a layout object
// Two layouts come already available in log4cpp
// unless you create your own.
// BasicLayout includes a time stamp
log4cpp::Layout* layout =
new log4cpp::BasicLayout();
// 3. attach the layout object to the
// appender object
app->setLayout(layout);
// 4. Instantiate the category object
// you may extract the root category, but it is
// usually more practical to directly instance
// a child category
log4cpp::Category main_cat =
log4cpp::Category::getInstance("main_cat");
// 5. Step 1
// an Appender when added to a category becomes
// an additional output destination unless
// Additivity is set to false when it is false,
// the appender added to the category replaces
// all previously existing appenders
main_cat.setAdditivity(false);
// 5. Step 2
// this appender becomes the only one
main_cat.setAppender(app);
// 6. Set up the priority for the category
// and is given INFO priority
// attempts to log DEBUG messages will fail
main_cat.setPriority(log4cpp::Priority::INFO);
// so we log some examples
main_cat.info("This is some info");
main_cat.debug("This debug message will
fail to write");
main_cat.alert("All hands abandon ship");
// you can log by using a log() method with
// a priority
main_cat.log(log4cpp::Priority::WARN, "This will
be a logged warning");
// gives you some programmatic control over
// priority levels
log4cpp::Priority::PriorityLevel priority;
bool this_is_critical = true;
if(this_is_critical)
priority = log4cpp::Priority::CRIT;
else
priority = log4cpp::Priority::DEBUG;
// this would not be logged if priority
// == DEBUG, because the category priority is
// set to INFO
main_cat.log(priority,"Importance depends on
context");
// You may also log by using stream style
// operations on
main_cat.critStream() << "This will show up
<< as " << 1 << " critical message"
<< log4cpp::CategoryStream::ENDLINE;
main_cat.emergStream() << "This will show up as "
<< 1 << " emergency message" <<
log4cpp::CategoryStream::ENDLINE;
// Stream operations can be used directly
// with the main object, but are
// preceded by the severity level
main_cat << log4cpp::Priority::ERROR
<< "And this will be an error"
<< log4cpp::CategoryStream::ENDLINE;
// This illustrates a small bug in version
// 2.5 of log4cpp
main_cat.debug("debug"); // this is correctly
// skipped
main_cat.info("info");
main_cat.notice("notice");
main_cat.warn("warn");
main_cat.error("error");
main_cat.crit("crit"); // this prints ALERT
// main_cat : crit
main_cat.alert("alert");// this prints PANIC
// main_cat : alert
main_cat.emerg("emerg");// this prints UNKOWN
// main_cat : emerg
main_cat.debug("Shutting down");// this will
// be skipped
// clean up and flush all appenders
log4cpp::Category::shutdown();
return 0;
}
</listing>
代码的最后一段描述了一个log4cpp中的bug。而在 BasicLayout() 中一个消息会被记录成这样的日志。
date_time PRIORITY category_name : message
下面是这段代码的输出。注意到crit()方法打印输出的是ALERT优先级,alert()方法打印的是PANIC优先级,而emerg()却打印了不确定的优先级。
<listing>
995871335 INFO main_cat : This is some info
995871335 PANIC main_cat : All hands abandon ship
995871335 WARN main_cat : This will be a logged warning
995871335 ALERT main_cat : Importance depends on context
995871335 ALERT main_cat : This will show up as 1
critical message
995871335 UNKOWN main_cat : This will show up as 1
emergency message
995871335 ERROR main_cat : And this will be an error
995871335 INFO main_cat : info
995871335 NOTICE main_cat : notice
995871335 WARN main_cat : warn
995871335 ERROR main_cat : error
995871335 ALERT main_cat : crit
995871335 PANIC main_cat : alert
995871335 UNKOWN main_cat : emerg
</listing>
原来实现自己的日志系统是如此的轻松,所以就将它应用到你的系统上来吧!