以文本方式查看主题

-  计算机科学论坛  (http://bbs.xml.org.cn/index.asp)
--  『 C/C++编程思想 』  (http://bbs.xml.org.cn/list.asp?boardid=61)
----  通用的应用程序高级日志系统  (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=85892)


--  作者:卷积内核
--  发布时间:7/27/2010 2:18:00 PM

--  通用的应用程序高级日志系统
日志模块

  本文介绍的日志系统包括七个 C++ 类:CLog, CFuncLog, IStoreLog, CWinLog, CFileLog, CAutoCritic, CLogSimpleLock。CLog 是所有日志模块中最主要的一个类,在大多数情况下,这个类在应用程序中最好是单实例的。但并不是必须的。重要性其次的一个类是 CFuncLog,这个类用于对函数调用的进入和退出进行记录。当然开发人员也可以使用这个类对任何数据进行日志记录。该类重载了 << 操作符,所以使用很方便。

下图是本文介绍的日志系统使用截图

按此在新窗口浏览图片

日志模块的 UML 设计

从下图可以看到,日志模块类可以分成两个部分:
1. Storage 类 —— 存储类
2. Logging 类 —— 日志类

按此在新窗口浏览图片

图一 UML 设计的类继承图

存储类:
IStoreLog 类的声明

/////////////////////////////////////////////////////////
// 此类是为一个抽象类,建立三个默认的函数,以便支持所有子类,
// 任何子类都必须支持缓冲和非缓冲存储
/////////////////////////////////////////////////////////
class IStoreLog
{
public:
virtual ~IStoreLog( void ){}; // 虚拟析构函数
virtual int FlushData() = 0;
virtual int WriteString( const std::string &Message ) = 0;
virtual int SetBufferLimit( long lSize ) = 0;
};
  存储类能对数据缓冲进行清扫处理,缺省情况下,该类在自己的缓冲中存储数据,并且只有调用 FlushData 函数才能将缓冲数据定向到磁盘或其它地方。一般情况下,存储类的缓冲受系统资源的限制,当缓冲达到限制时它会自动进行清理。建立缓冲限制使用 SetBufferLimit 函数。默认情况下,存储类实现必须要分配缓冲并只能用 SetBufferLimit 函数改变缓冲的大小。
  存储类使用 WriteString 函数来存储串。所以它既可以存储格式化串,也能存储原始非格式化数据。

日志类

  这一部分我们要讨论两个类:CLog 和 CFuncLog。CLog 在 clog.h 中声明,实现文件是 clog.cpp,CFunLog 在 cfunlog.h 声明,实现文件是 cfunlog.cpp。
  日志类有一个很特别的函数,使用它来记录日志很容易,你可以对其跟踪输出进行配置:如果你不需要记录时间,只要用 SetLogTime 将 CLog 类的标志设为 FALSE 即可。此外你还可以调用 SetTimeFormat 来改变时间的输出格式。缺省情况下,该类使用长时间格式。在头文件的开始处有两个很有用的时间格式定义。第一个是带秒输出的长格式,第二个是不带秒输出的短格式:

#define DEF_TIME_LONG_STR "%02u:%02u:%02u ms:%03u"
#define DEF_TIME_SHORT_STR "%02u:%02u:%02u"
警告:格式串最多四个,否则会有堆栈溢出错误

CLog 还能具备如下的属性:

信息输出格式属性——SetMessageFormat 和 GetMessageFormat 函数;
AutoFlush 属性——SetAutoFlush 和 GetAutoFlush 函数;如果是 true,则每次跟踪信息都将缓冲数据存入磁盘,这对应用程序处于alpha测试和代码中存在一般保护性错误时非常有用。第二种模式主要用于记录应用程序的控制状态以及应用程序的执行时间不是很重要时——这是日志系统的顶层性能模式。

在 CLog 类中有三个日志记录函数:

LogRawString —— 跟踪记录原始串,不需要格式化存储;
LogString —— 跟踪记录特定级别和格式的日志信息,有两个函数名字都相同,其差别是输出格式不同,两种格式是:

std::string
char*
LogFormatString —— 格式化函数,实际上是对 printf 函数的封装。

  大多数情况下,开发人员如果需要超过三种类型以上的信息,可以实现 CLog 提供的一个虚拟函数 LevelText,在参数中提供一个表示日志级别 LEVEL 的数字。函数将用串形式返回一个类型名。默认情况下,一种类型规定的格式符号限制是12种,但可以用 SetMessageFormat 函数修改格式模板串。

如果要在应用程序中使用日志机制,请在工程中包含下列头文件:

#include "clog.h"
#include "cfunclog.h"
#include "cwinlog.h"  // 在 GUI 窗口中显示日志信息时包含
#include "cfilelog.h"  // 将日志信息写入文件时包含
...
CFuncLog 类不是必须的,它只是简化一些日志模块的功能,如:进入函数和退出函数。
特殊格式和所有主要的日志操作都在 CLog 类中实现。所以你的选择很灵活。

注意:CWinLog 类存储跟踪窗口中的信息,它不是多进程安全的。但多进程的日志可以使用 CFileLog 类。它将所有跟踪信息存储到文件。所有文件的操作通过操作系统进行同步。

如何使用日志模块

1、创建 CLog 类实例:

CLog *m_pLog = new CLog( new CFileLog( "c:\\log.log" ), LOG_MAX_LEVEL, true );
  CLog 构造函数的第一个参数必须是 IStoreLog 接口指针。日志模块中有两个 IStoreLog 实现:一个是 CWinLog,另一个是 CFileLog。前者创建 GUI 窗口,并在窗口中显示日志信息,后者将日志信息存储到文件中。由于输出文件可被用于任何 OS 设备或命名管道等,它使用 CreateFile API 函数处理。
  CLog 构造函数的第二个参数是日志信息的级别,可以根据需要来设置。所以,如果将它设置为 0,则输出日志仅为 ERROR 信息。如果设置为 1,则日志输出为 ERROR 和 WARNING 信息.....
  第三个参数针对 CLog 实例的,说明这个实例是否为 IStoreLog 的父类。缺省值为 true。所以 CLog 类的析构函数要删除 IStoreLog 类的实例。
  如果你想要日志函数的进入和退出,可以向下面这样:

CRepTestApp::CRepTestApp()
{
 CFuncLog log( m_pLog, "CRepTestApp::CRepTestApp" );
 ...
}
  上面的代码将在进入函数和退出函数时记录日志。这里使用了自动变量的特性。进入函数时,构造函数记录“enter.....”信息,退出函数时,析构函数在日志中记录“leave......”,如果还想添加其它的日志信息,可以用如下代码:

int something = 100;
log << something;
...
警告:操作符 << 以原始格式存储日志信息。

使用 CFuncLog 类的 LogString 可以很容易添加需要的信息到日志中。

  如果你想要将存储到其它地方,那么必须自己实现 IStoreLog 类,并用其实例作为某个构造函数的参数。CAutoCritic 和 CLogSimpleLock 类是对 Windows 临界区 API 的封装。这个类是在单独的文件中实现的,并在名字空间 LOGGER 中使用。你可以通过其它的 IStoreLog 类灵活使用。

[URL=http://www.vckbase.com/code/downcode.asp?id=3179]源代码下载[/URL]


W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
31.250ms