问题:
在很多应用中,需要记录程序运行过程中的关键信息、关键操作、警告和异常等。这些信息可以被用来追溯、调试和排错、分析运行时环境,或者用于其他特定的用途。一些长期运行的、无人监控的或者运行在后台不带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 )
{
aHandler( this, args );
}
}
这样一来,凡是在CLoggerAbstract中登记的函数都能够适时得到写入日志的信息。CLoggerAbstract提供了一组方法,用以登记和取消登记。
/// <summary>
/// 设置写日志时触发的外部方法
/// </summary>
-->
- 该日志由 48775959 于10年前发表在综合分类下,最后更新于 2013年12月02日.
- 转载请注明: Windows平台下程序日志的设计和实现(上:设计、实现和应用) | 学步园 +复制链接