大家好,又见面了,我是你们的朋友全栈君。
代码语言:javascript复制1、log4cpp的下载安装与配置 官方网站http://log4cpp.sourceforge.net/有下载地址,安装过程配置选项及测试用例。Linux下将下载好的tar包解压到/usr/local/下运行./configure(如有需要添加相关配置选项),使用make编译,使用make check进行检测,使用make install安装,使用之前的相关命令安装好之后在/usr/local/include/和/usr/local/lib/文件夹下会有相关的文件。使用g 编译测试用例时需要链接相关的库文件,根据提示进行链接-llog4cpp-lpthread。根据测试用例的相关信息,查看安装是否成功。2、由测试用例来看log4cpp的处理流程 2.1 几个重要的概念 Category(种类)负责向日志中写入信息
代码语言:javascript复制 Appender(附加目的地)负责制定日志的目的地。例如FileAppender、RollingFileAppender 、OstreamAppender、StringQueueAppender、 Win32DebugAppender、 NTEventLogAppender
代码语言:javascript复制 Layout(布局)负责设定日志的格式。例如BasicLayout 、SimpleLayout、 PatternLayout
代码语言:javascript复制 Priority(优先级)
代码语言:javascript复制 NDC(嵌套的诊断上下文) 2.2 log4cpp记录日志的原理 每个Category都有一个优先级,该优先级可以由setPriority方法设置,或者从其父Category中继承而来。每条日志也有一个优先级。当 Category记录该条日志时,若日志的优先级高于Category的优先级时,该日志将被记录,否则被忽略
以下是在priority.hh中定义的相关优先级,数字越小优先级越高
typedef enum
{EMERG = 0,
FATAL = 0,
ALERT = 100,
CRIT = 200,
ERROR = 300,
WARN = 400,
NOTICE = 500,
INFO = 600,
DEBUG = 700,
NOTSET = 800
} PriorityLevel;
2.3 测试用例
// main.cpp
#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;
}
1352973121 ERROR : root error
1352973121 ERROR sub1 : sub1 error
1352973121 WARN sub1 : sub1 warn
1352973121 WARN : 1 1 == two ?
1352973121 ERROR : Streamed root error
1352973121 ERROR sub1 : Streamed sub1 error
1352973121 WARN sub1 : Streamed sub1 warn
1352973121 ERROR : Another streamed error
流程分析:
1、
创建Appender并指定其包含的Layout(本例中创建了OstreamAppender的appender1和FileAppender的appender2,它们指定的Layout都是BasicLayout)
2、从系统中得到Category的根,分别将Appender添加到相应的Category中(appender1添加到了root,appender2添加到了sub1)
3、设置Category的优先级(对root设置了优先级为WARN)
4、记录日志
5、内存释放(Log4cpp使用了一个内部类来管理这些对象。此类的名称是HierarchyMaintainer,它负责管理Category的继承关系,在程序结束时,HierarchyMaintainer会依次释放所有Category,而Category则会依次释放拥有的有效Appender,Appender则会释放所有附属的Layout。)
由结果可以看出由于root设置了优先级为WARN,日志消息ERROR和INFO中只有ERROR可以打印出,sub1没有设置优先级,ERROR和WARN都可以显示出。
3、Layout
Layout规定了日志消息的显示格式,在源代码中有多个类来描述显示格式。它们之间的关系如下图:
基类Layout是一个抽象类,派生类BasicLayout和SimpleLayout以及PatternLayout都继承自它。在PatternLayout类中使用
setConversionPattern函数
来设置日志的输出格式。
函数原型为void setConversionPattern(string& conversionPattern) throw(ConfigureFailure);该函数的参数类型为string,目的是使用格式化的字符串来描述输出格式。具体含义如下:
%c category;(CategoryNameComponent)
%d 日期;(TimeStampComponent)日期可以进一步的设置格式,用花括号包围,例如%d{%H:%M:%S,%l} 或者 %d{%d %m %Y%H:%M:%S,%l}。如果不设置具体日期格式,则如下默认格式被使用“Wed Jan 02 02:03:55 1980”。日期的格式符号与ANSI C函数strftime中的一致。但增加了一个格式符号%l,表示毫秒,占三个十进制位。
%m 消息;(MessageComponent)
%n 换行符,会根据平台的不同而不同,但对于用户透明;
%p 优先级(PriorityComponent)
%r 自从layout被创建后的毫秒数(MillisSinceEpochComponent);
%R 从1970年1月1日0时开始到目前为止的秒数(SecondsSinceEpochComponent);
%u 进程开始到目前为止的时钟周期数(ProcessorTimeComponent);
%x NDC(NDCComponent)。
让我们看看源代码是如何使用这些格式化字符串的
while(...){
...
switch (ch) {
case '%':
literal = ch;
break;
case 'm':
component = new MessageComponent();
break;
case 'n':
{
std::ostringstream endline;
endline << std::endl;
literal = endline.str();
}
break;
case 'c':
component = new CategoryNameComponent(specPostfix);
break;
case 'd':
component = new TimeStampComponent(specPostfix);
break;
case 'p':
component = new PriorityComponent();
break;
case 'r':
component = new MillisSinceEpochComponent();
break;
case 'R':
component = new SecondsSinceEpochComponent();
break;
case 't':
component = new ThreadNameComponent();
break;
case 'u':
component = new ProcessorTimeComponent();
break;
case 'x':
component = new NDCComponent();
break;
...
}
在PatternLayout类中内嵌了PatternComponent类,MessageComponent、CategoryNameComponent...等这些类分别继承于PatternComponent类。PatternComponent中定义了append函数。
函数原型为virtual void append(ostringstream& out, const LoggingEvent& event) = 0;该函数的基本功能是将日志事件的相关信息以某种方式写入ostringstream流中。不同的Component继承了PatternComponent都会按照各自的方式来实现append函数
4、Appender
主要介绍以下Appender:
log4cpp::FileAppender // 输出到文件
FileAppender(const string& name, const string& fileName, bool append = true, mode_t mode = 00644);
FileAppender(const string& name, int fd);
第一个构造函数中参数含义分别指的是appender的名字,日志文件的名字,在日志文件之后记录日志还是清空日志文件再记录,文件的打开方式。第二个构造函数参数的含义是appender的名字,日志文件的文件描述符
log4cpp::RollingFileAppender // 输出到回卷文件,即当文件到达某个大小后回卷
RollingFileAppender(const string& name, const string& fileName,size_t maxFileSize = 10*1024*1024, unsigned int maxBackupIndex = 1, bool append = true, mode_t mode = 00644);
maxFileSize表示回滚文件的最大值,当文件大小超过该值10M时,回滚记录。maxBackupIndex指出了回滚文件所用的备份文件的最大个数。
log4cpp::OstreamAppender // 输出到一个ostream类
OstreamAppender(const string& name, ostream* stream);第一个参数指定appender的名字,第二个参数指定关联的流指针
log4cpp::StringQueueAppender // 内存队列
StringQueueAppender(const string& name);参数为appender指定名字,功能是将日志记录到一个字符串队列中,通过相关的方法对queue进行操作
log4cpp::Win32DebugAppender // 发送到缺省系统调试器
Win32DebugAppender(const string& name);参数为appender指定名字
log4cpp::NTEventLogAppender //发送到win事件日志
该Appender可以将日志发送到windows的日志,在运行程序后可以打开windows的计算机管理->系统工具->事件查看器->应用程序。
NTEventLogAppender(const std::string& name, const std::string& sourceName);第一个参数指出appender的名字,第二个参数指出日志文件的名字。
5、Category
该类中Category的构造函数被protected修饰,在类外无法构造对象,类中提供了两个static函数构造对象,分别是getRoot和getInstance。在大多数情况下,一个应用程序只需要一个日志种类(Category),但是有时也会用到多个Category,此时可以使用根Category的getInstance方法来得到子Category。不同的子Category用于不同的场合。
6、NDC(nested DiagnosticContext)
嵌套的诊断上下文,A Nested Diagnostic Context, or NDC in short, is an instrument to distinguish interleaved(交错) log output from different sources. Log output is typically interleaved when a server handles multiple clients near-simulatanously.(几乎同时的)Interleaved log output can still be meaningful if each log entry from different contexts had a distinctive stamp(标记). This is where NDCs come into play.
NDC是一种用来区分不同源代码中交替出现的日志的手段。当一个服务端程序同时记录好几个并行客户时,输出的日志会混杂在一起难以区分。但如果不同上下文的日志入口拥有一个特定的标识,则可以解决这个问题。NDC就是在这种情况下发挥作用。注意NDC是以线程为基础的,每个线程拥有一个NDC,每个NDC的操作仅对执行该操作的线程有效。
Note that NDCs are managed on a per thread basis. NDC operations such as <code>push</code>, <code>pop</code>, <code>clear</code>, <code>getDepth</code> and <code> setMaxDepth</code> affect the NDC of the current thread only. NDCs of other threads remain unaffected.
下图指出了类中函数的调用关系:
常用的一些静态函数xxx()内部首先调用getNDC()函数得到一个NDC对象,之后继续调用对应的_xxx()虚函数。例如:
void NDC::clear()
{
getNDC()._clear();
}
几乎所有静态函数的都通过上面这个例子来实现,所有虚函数的操作对象都是_stack,它是一个用vector容器模拟的栈。
参考:
Log4cpp介绍及使用http://blog.csdn.net/kingskyleader/article/details/7320826
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/158398.html原文链接:https://javaforall.cn
如果您是在找激活码,但输入激活码后激活失败,最新激活码地址:https://javaforall.cn/127239.html