Qt下的Log记录库 log4qt   < src="http://blog.csdn.net/count.aspx?ID=2177781&Type=Rank" type="text/javascript">   

但凡稍许有些规模的软件系统,都需要一个事件记录系统,将各类调试或者错误信息输出到文件或者控制台上,特别是软件发布后,很多情况下开发人员只需要凭借事件记录就可以诊断软件故障所发生的位置。

我目前使用Qt所开发的一款系统也不例外,不过一开始我使用了一个自己写的Log记录用的全局类,直接将各类要记录的信息写入到文本文件中,简单归简单不过也足够使用了,因此我也从没想过要真正将它完善。直到最近忽然兴起,决心用一套真正完善的Log记录库赖替换掉它,最先想到的自然是log4cpp这个C++下最常用的Log库,但是下载来代码,尝试编译时却发现这套代码竟然没有供VS2005编译使用的Project文件,当然可以自己建立工程,但是看到那成堆的代码文件我就退缩了,另外一个更严重的问题是我原来自己实现的Log记录类至少能使用QObject的Meta信息来记录出事件所属的类的类名,而log4cpp这样的通用类库是不可能支持这样的功能的(除非自己写新的类进去)。这样看来log4cpp不是很适合我了。于是鬼使神差之中我在Google中搜索了log4qt这个名字,没想到竟然被我找到了:
http://sourceforge.net/projects/log4qt/

这个库的规模适中,大约4、5十个文件的样子,直接将它们加入我的工程,我就开始log4qt之旅了:花了10分钟将所有文件加入工程,编译,竟然出错,似乎是vs2005的编译审核严格了一些而已,修改之,再编译,这次Link出错,哦,是我忘了加moc,大约又花了15分钟逐个文件加上moc,ok,编译通过,运行,程序竟然崩溃,没办法只好跟进代码寻找原因,花了N久,结果发现是在QFile打开stderr和stdout时Qt内部发生的错误,Google了一下,无果,暂时屏蔽了这些代码,OK,程序运行起来了,不过我屏蔽的代码是这个log类初始化时默认将事件记录到控制台的代码,因此增加了一些设置代码,将log输出定位到文本文件中,好了,log总算能正常出现了。

log4qt的帮助文档很详细,可惜就是缺少一个傻瓜教程教我怎样以最简单的方法记录log,仔细的浏览了一遍帮助后,我才找到了对Qt程序最简单有效的log输出方法,那就是在自己的类中的QT_OBJECT宏指令之后,增加一条LOG4QT_DECLARE_QCLASS_LOGGER的指令,像这样,够简单吧:
#include  " log4qt/logger.h "

class  QMyClass:  public  QObject
{
    Q_OBJECT
    LOG4QT_DECLARE_QCLASS_LOGGER

public:
    ...................

}
;

这个宏的具体内容如下(在logger.h中定义),这相当于在这个类中增加了一个类成员,并且使用logger()函数就可以访问到它:
     #define  LOG4QT_DECLARE_QCLASS_LOGGER                                      
        
private :                                                              
            mutable Log4Qt::ClassLogger mLog4QtClassLogger;                   
        
public :                                                               
            inline Log4Qt::Logger 
* logger()  const                              
            
{   return mLog4QtClassLogger.logger(this);    }                   
        
private :

现在,在这个类中就可以直接使用 logger()->error("Error Message"); 的方式来记录Log了,记录出的信息中会直接带上当前类的类名。

log4qt库包括以下几种类供用户组合使用:
1)Logger,用于供要记录log的类使用,向log4qt系统加入信息,比如刚才的那个用于记录log的宏,其幕后就是一个名为ClassLogger的类在工作。
2)Appender,用于将Log记录到指定的媒介上,比如有ConsoleAppender,将Log信息输出到控制台上,FileAppender,将Log信息数到到文件中。可以向log4qt库同时指定多个Appender,则各类事件就会同时被输出到多个媒介上了。
3)Layout,指定Log输出时的格式,比如是否要带有当前日期时间,是否带有当前的类名,等等。

正如前面说的,log4qt库默认情况下会将log信息输出到控制台上,如果需要改变这个规则的话,可以在系统初始化的时候,自行制定log4qt的Appender,和Layout等内容,比如以下是我的代码,将Log信息同时输出到文件和控制台:
    Log4Qt::Logger  * logger  =  Log4Qt::Logger::rootLogger();
    logger
-> removeAllAppenders();
    
// FileAppender
    Log4Qt::FileAppender  * fileappender  =   new  Log4Qt::FileAppender();
    fileappender
-> setName( " FileAppender " );
    QFileInfo fileinfo(mUserPath.GetUserSubPath(
" logs " ), QDateTime::currentDateTime().toString( " yyyyMMdd_hhmmss " +   " .log " );
    fileappender
-> setFile(fileinfo.filePath());
    Log4Qt::TTCCLayout 
* filelayout  =   new  Log4Qt::TTCCLayout(Log4Qt::TTCCLayout::DateFormat::ISO8601);
    fileappender
-> setLayout(filelayout);
    fileappender
-> activateOptions();
    logger
-> addAppender(fileappender);
#ifdef _DEBUG
    
// ConsoleAppender
    Log4Qt::ConsoleAppender  * consoleappender  =   new  Log4Qt::ConsoleAppender();
    consoleappender
-> setName( " ConsoleAppender " );
    consoleappender
-> setTarget(Log4Qt::ConsoleAppender::STDOUT_TARGET);
    
// Log4Qt::SimpleLayout *consolelayout = new Log4Qt::SimpleLayout();
    Log4Qt::TTCCLayout  * consolelayout  =   new  Log4Qt::TTCCLayout(Log4Qt::TTCCLayout::DateFormat::ISO8601);
    consoleappender
-> setLayout(consolelayout);
    consoleappender
-> activateOptions();
    logger
-> addAppender(consoleappender);
#endif

好了,还剩下两件事:
1)关于QFile打开stderr和stdout时会导致程序崩溃的问题,看来这个是Qt4.3.0在Vista系统下的Bug,我换成了Qt4.3.4后就没有这个问题了。
2)关于用VS2005编译时又错误的问题,我已把修改过的地方告知作者了,现在的版本应该不会有问题了吧。