Windows平台下程序日志的设计和实现(上:设计、实现和应用)

** 问题: ** **

**

在很多应用中,需要记录程序运行过程中的关键信息、关键操作、警告和异常等。这些信息可以被用来追溯、调试和排错、分析运行时环境,或者用于其他特定的用途。一些长期运行的、无人监控的或者运行在后台不带 UI 的程序,记录运行时的日志尤其重要。

** 目标: ** **

**

1、 实现日志记录功能。

2、 模块容易使用、容易扩展、可灵活配置。

3、 日志内容分类输出。

** 约束: ** **

**

Windows 平台 .net 架构

** 方案: ** **

**

1、 可以向文件、数据库和 Windows 事件日志中记录日志( 打开 Windows 的 “ 控制面板 / 管理工具 / 事件查看器 ” ,系统显示 Windows 事件日志 ),并通过配置文件灵活配置。

2、 可以容易地增加其他的日志输出源。

3、 写入日志源的同时,可以把控制“委托( delegate )”给外部入口。通常用这个办法通知监控程序。例如,在写日志的同时,将日志信息“委托”输出到用户界面的一个 ListBox 中,管理员可以在ListBox中适时看到日志信息。

4、 日志分类输出: DEBUG < INFO < WARN < ERROR < FATAL 。 小于预定级别的日志不输出。

** 设计: ** **

**

1 、设计类图:

2 、设计思路:

名称

|

类型

|

功能描述

---|---|---

ILogger

|

接口

|

日志模块的接口,对外约定了操作日志的公共方法。

CLoggerAbstract

|

抽象类

|

CLoggerAbstract 实现接口 ILogger。

在 CLoggerAbstract 中实现了日志操作的通用方法,是日志实现的框架。向具体输出源写入日志的操作通过子类实现CLoggerAbstract的抽象函数来实现。

这是一个典型的使用继承的 Template模式(Template模式的另外一种实现方法是使用聚合)。

CLoggerAbstract中包含一个List,用以记录所有向日志登记的外部入口函数。一旦写日志的动作发生,CLoggerAbstract调用所有登记的入口函数,并把日志信息作为参数传入。这是一个观察者模式。

CLoggerFil

CLoggerDatabase

CLoggerEvent

|

|

分别继承自抽象类 CLoggerAbstract,它们分别实现了向文件、数据库和Windows事件日志写入日志的具体操作。

上述三个类和 CLoggerAbstract 类构成了模板模式。

CLoggerFactory

|

|

提供静态方法创建具体的日志处理类( CLoggerFile、CLoggerDatabase、CLoggerEvent)。

这是一个工厂模式。

** 实现: ** **

**

关键部分的实现。

1、 接口 ILogger

public interface ILogger

{

// 写日志

void debug( string message, string source );

void info ( string message, string source );

void warn ( string message, string source );

void error( string message, string source );

void fatal( string message, string source );

// 设置和返回日志输出级别

void setLevel(enumLevel level);

enumLevel getLevel();

// 管理外部程序处理入口

void addEntryWrittenHander( Delegate handler );

void clearEntryWrittenHander();

void enableEntryWrittenHander( bool enabled );

}

2、 模板方式的实现

在抽象类 CLoggerAbstract 中声明了抽象方法:

// 抽象函数,具体的写日志操作由子类实现

public abstract void _ writeLog ( string message, string source, enumLevel type);

CLoggerAbstract 中写日志的代码 (以 debug()为例):

if ( _outputLevel <= enumLevel.DEBUG ) // 实现日志分级输出

write ( message, source, enumLevel.DEBUG );

CLoggerAbstract 的 write() 实际调用了抽象函数 _writeLog():

private void write( string message, string source, enumLevel type )

{

try

{

** _writeLog( message, source, type ); // 调用抽象方法

**

OnEntryWritten( message, source, type );

}

catch ( Exception ex )

{

Trace.WriteLine("Write logger error:" + ex.Message);

}

}

抽象函数 _writeLog()的具体实现在各个子类中,因日志输出源的不同而有不同的版本。整个的运算逻辑在模板类中(这里是抽象类 CLoggerAbstract ),具体类只是填充了模板类的空白。这样做,达到了代码复用的目的,并且使业务逻辑更加清晰。

3、 管理外部处理入口函数

CLoggerAbstract 中包含一个 List ,用来保存所有登记的外部处理入口函数:

// 写日志时触发外部方法的HANDLE

private static ArrayList _entryWrittenEventHandler = new ArrayList();

当 CLoggerAbstract 写入日志的时候,依次调用 _ entryWrittenEventHandler 中登记的函数,并把当前写入的日志内容作为参数传给这些函数:

if ( _entryWrittenEventHandler.Count >0 )

{

myLogEntryWrittenArgs args = new myLogEntryWrittenArgs();

args.Entry.TimeWritten = DateTime.Now;

args.Entry.Message = message;

args.Entry.Type = type;

args.Entry.Source = source;

foreach ( myLogEntryWrittenHandler aHandler in _entryWrittenEventHandler )

{

&nbs

Published At
Categories with Web编程
Tagged with
comments powered by Disqus