前面已经说完了怎样使用log4cxx进行日志记录,今天发现问题稍有点复杂。原因是系统中用到的一个dll已经使用了log4cxx。我们在开发的过程中也想使用log4cxx,但不想与DLL中的日志写到同一个文件中,问题就来了,怎样区别打印到不同的文件中呢,DLL中采用的为应该为getRootLogger的方式。
这个网址中的文章很好,解决方案主要参考此文:http://www.open-open.com/doc/view/4bf2bd4f517c4044b1f7d4e2d22eccaf
log4cxx主要是由三部分组成:loggers, appenders和layouts.这三个主要组成部分,协同协作能够使我们根据实际的需要进行日志的输出,它们规定了日志信息的类型和级别,控制应用程序运行时的日志信息组成方式以及日志记录的输出方式。
Logger是Log4cxx的核心,Logger具有继承关系的层次结构,最顶层为RootLogger,每个Logger都有一个级别(Level),每个Logger可以附加多个Appender.Appender代表了日志输出的目标,对于每一个Appender可以通过Layout进行格式配置。
Logger命名:保持Logger与其所在的类的名称一致的方法是目前所知的最好的命名策略。
一个关于Logger继承的例子:
#设置root logger 为DEBUG级别,使用了ca, fa两个Appender
log4j.rootLogger = DEBUG, ca, fa
#设置list logger
log4j.logger.list = DEBUG, listApp
#设置list.voice logger
log4j.logger.list.voice= INFO, listVoice, listVoiceBak
list是list.voice的父亲Logger, list.voice是list的儿子Logger. rootLogger是根Logger, 在此例中list和list.voice两个Logger又都继承了rootLogger,不过只是继承了Appenders,Level并没有继。(此解有待验证)
还是看配置文件:log4cxx.properties
# 设置root logger为DEBUG级别,使用了ca和fa两个Appender
log4j.rootLogger=DEBUG, fa, ca
# 设置.listApp logger,屏蔽logger-list的LEVEL继承
log4j.logger.listApp=DEBUG, listApp
# 设置.listApp2 logger,屏蔽logger-list的LEVEL继承
log4j.logger.listApp2=DEBUG, listApp2
#屏蔽listApp的Appender继承
log4j.additivity.listApp=false
#屏蔽listApp2的Appender继承
log4j.additivity.listApp2=false
#对Appender fa进行设置:# 这是一个文件类型的Appender,
log4j.appender.fa=org.apache.log4j.FileAppender
log4j.appender.fa.ImmediateFlush=true
# 其输出文件(File)为 Runlog.log,
log4j.appender.fa.File=Runlog.log
log4j.appender.fa.layout=org.apache.log4j.PatternLayout
# 输出方式(Append)为覆盖方式,
log4j.appender.fa.Append=false
# 输出格式(layout)为PatternLayout
log4j.appender.fa.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %.16c - %m%n
#对Appender ca进行设置:
# 这是一个控制台类型的Appender
log4j.appender.ca=org.apache.log4j.ConsoleAppender
# 输出格式(layout)为PatternLayout
log4j.appender.ca.layout=org.apache.log4j.PatternLayout
log4j.appender.ca.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %.16c - %m%n
#对Appender listApp进行设置# 这是一个文件类型的Appender,
log4j.appender.listApp=org.apache.log4j.FileAppender
#立即写入日志文件
log4j.appender.listApp.ImmediateFlush=true
# 其输出文件(File)为 listApp.log
log4j.appender.listApp.File=listApp.log
# 输出方式(Append)为覆盖方式,
log4j.appender.listApp.Append=false
log4j.appender.listApp.layout=org.apache.log4j.PatternLayout
log4j.appender.listApp.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %.16c - %m%n
#对Appender listApp2进行设置
log4j.appender.listApp2=org.apache.log4j.FileAppender
log4j.appender.listApp2.ImmediateFlush=true
log4j.appender.listApp2.File=listApp2.log
log4j.appender.listApp2.Append=false
log4j.appender.listApp2.layout=org.apache.log4j.PatternLayout
log4j.appender.listApp2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %.16c - %m%n
以下为实现代码:
// testlog4cxx.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <log4cxx/logger.h>
#include <log4cxx/propertyconfigurator.h>
using namespace log4cxx;
using namespace log4cxx::helpers;
int _tmain(int argc, _TCHAR* argv[])
{
PropertyConfigurator::configure("log4cxx.properties");
LOG4CXX_INFO(log4cxx::Logger::getLogger("list5"), "list,log4cxx!");
LOG4CXX_INFO(log4cxx::Logger::getLogger("list5"), "list,mylog4cxx!");
LOG4CXX_INFO(log4cxx::Logger::getLogger("listApp"), "listApp,log4cxx!");
LOG4CXX_INFO(log4cxx::Logger::getLogger("listApp2"), "listApp2, hello world!");
return 0;
}
将log4cxx.properties与生成后的testlog4cxx.exe放置同一目录,运行后发现目录下生成三个文件,分别为:他们的文件名及内容分别为
Runlog.log:
2012-04-06 21:13:56 INFO list5 - list,log4cxx!
2012-04-06 21:13:56 INFO list5 - list,mylog4cxx!
listApp.log:
2012-04-06 21:13:56 INFO listApp - listApp,log4cxx!
2012-04-06 21:13:56 INFO listApp - listApp TimeRsp.nErrno: 123
listApp2.log:
2012-04-06 21:13:56 INFO listApp2 - listApp2, hello world!
由此可以看出,所有Logger默认继承于rootLogger的Appender,一般情况下(Level级别允许)总会在Runlog.log中打出,若想有所例外,需用配置log4j.additivity.AppenderName = false将默认继承去除。