Windows平台下程序日志的设计和实现(下:代码)

1、CConfiguration.cs

using System;
using System.Collections.Specialized;
using System.Xml;
using System.Configuration;

namespace com.lenovo.zhangyuk.logger
{
///

1<summary>   
2/// CConfiguration 的摘要说明。   
3/// </summary>

public class CConfiguration
{
// 程序全局配置(配置文件相应内容在内存中的映射)
private static NameValueCollection _configration = new NameValueCollection();

private CConfiguration()
{
}

///

1<summary>   
2/// 取配置项   
3/// </summary>

///

1<param name="key"/>

///

1<returns></returns>

public static string getConfiguration( string key )
{
// 如果第一次取配置项,那么将所有配置项从文件读入内存,否则从内存中取出。
if( _configration.Count==0 )
{
_configration = ConfigurationSettings.AppSettings;
}

return (null != _configration[key]) ? _configration[key].ToString().Trim() : "";
}
}
}

2、ILogger.cs

using System;
using System.Diagnostics;

namespace com.lenovo.zhangyuk.logger
{
///

1<summary>   
2/// 日志输出级别   
3/// </summary>

public enum enumLevel
{
DEBUG,
INFO,
WARN,
ERROR,
FATAL
}

///

1<summary>   
2/// 日志内容,参考 myLogEntryWrittenArgs   
3/// </summary>

public class myEventLogEntry
{
///

1<summary>   
2/// 日志源,用以记载日志的来源   
3/// </summary>

public string Source = "";
///

1<summary>   
2/// 日志内容   
3/// </summary>

public string Message = "";
///

1<summary>   
2/// 写入日志的时间   
3/// </summary>

public DateTime TimeWritten = DateTime.Now;
///

1<summary>   
2/// 日志的类型,可以参考 EventLogEntryType 的定义   
3/// </summary>

public enumLevel Type = enumLevel.INFO;
}

///

1<summary>   
2/// 日志外部处理函数的参数   
3/// </summary>

public class myLogEntryWrittenArgs : EventArgs
{
public myLogEntryWrittenArgs()
{
Entry = new myEventLogEntry();
}

public myEventLogEntry Entry;
}

///

1<summary>   
2/// 日志外部的处理入口函数声明   
3/// </summary>

public delegate void myLogEntryWrittenHandler( object sender, myLogEntryWrittenArgs e );

///

 1<summary>   
 2///   
 3/// 根据日志输出级别写日志   
 4///   
 5/// 特性:   
 6///   
 7/// 1、可以根据日志输出级别写日志   
 8///   
 9/// 日志的输出级别:DEBUG &lt; INFO &lt; WARN &lt; ERROR &lt; FATAL   
10///   
11/// 例如,日志级别是 INFO,则调用 debug() 不会输出,调用其他方法会输出;   
12/// 日志级别是 WARN,则调用 debug() 和 info() 不会输出,调用其他方法会输出。   
13///   
14/// 2、写日志时调用外部处理入口   
15///   
16/// 可以添加外部处理入口函数(声明见 myLogEntryWrittenHandler ),在写日志时,程序   
17/// 依次调用外部处理入口函数,调用着可以在外部处理入口函数中得到日志的相关信息。   
18/// 这里使用了观察者模式。   
19///   
20/// 例如:   
21/// private static ILogger logger = CLoggerFactory.getLogger();   
22/// public void logEntryWritten(object sender, myLogEntryWrittenArgs e)   
23/// {   
24/// //......   
25/// }   
26/// logger.addEntryWrittenHander( new myLogEntryWrittenHandler(this.logEntryWritten) );   
27///   
28/// 那么在写日志的时候,logEntryWritten()会被调用。   
29///   
30/// </summary>

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 );
}
}

3、CLoggerAbstract.cs

using System;
using System.IO;
using System.Diagnostics;
using System.Collections;

namespace com.lenovo.zhangyuk.logger
{
///

1<summary>   
2/// 日志处理的抽象类   
3///   
4/// 这里使用了基于继承的模板模式   
5/// 在CLoggerAbstract中实现了向各种日志源输出的通用操作   
6/// 向具体日志源输出的动作则通过虚函数_writeLog在子类实现   
7/// </summary>

abstract class CLoggerAbstract : ILogger
{
// 写日志时触发外部方法的HANDLE
private static ArrayList _entryWrittenEventHandler = new ArrayList();

// 写日志时是否触发外部方法
private static bool _bEnableEntryWritten = true;

// 日志输出级别,默认是 INFO
private static enumLevel _outputLevel = enumLevel.INFO;

// 抽象函数,具体的写日志操作由子类实现
public abstract void _writeLog(string message, string source, enumLevel type);

///

1<summary>   
2/// 构造函数   
3/// </summary>

///

1<param name="strEventSource"/>

///

1<param name="strEventLog"/>

public CLoggerAbstract( enumLevel level )
{
_outputLevel = level;
}

///

1<summary>   
2/// 设置日志输出级别   
3/// </summary>

///

1<param name="level"/>

级别
public void setLevel(enumLevel level)
{
_outputLevel = level;
}

///

1<summary>   
2/// 获得日志输出级别   
3/// </summary>

///

1<returns>级别</returns>

public enumLevel getLevel()
{
return _outputLevel;
}

///

1<summary>   
2/// 写调试信息   
3/// </summary>

///

1<param name="message"/>

public void debug( string message, string source )
{
if( _outputLevel <= enumLevel.DEBUG )
write( message, source, enumLevel.DEBUG );
}

///

1<summary>   
2/// 写一般信息   
3/// </summary>

///

1<param name="message"/>

public void info( string message, string source )
{
if( _outputLevel <= enumLevel.INFO )
write( message, source, enumLevel.INFO );
}

///

1<summary>   
2/// 写警告信息   
3/// </summary>

///

1<param name="message"/>

public void warn( string message, string source )
{
if( _outputLevel <= enumLevel.WARN )
write( message, source, enumLevel.WARN );
}

///

1<summary>   
2/// 写错误信息   
3/// </summary>

///

1<param name="message"/>

public void error( string message, string source )
{
if( _outputLevel <= enumLevel.ERROR )
write( message, source, enumLevel.ERROR );
}

///

1<summary>   
2/// 写严重错误信息   
3/// </summary>

///

1<param name="message"/>

public void fatal( string message, string source )
{
if( _outputLevel <= enumLevel.FATAL )
write( message, source, enumLevel.FATAL );
}

///

1<summary>   
2/// 设置写日志时触发的外部方法   
3/// </summary>

///

1<param name="handler"/>

外部方法HANDLE
public void addEntryWrittenHander( Delegate handler )
{
try
{
if( !_entryWrittenEventHandler.Contains(handler) )
_entryWrittenEventHandler.Add( handler );
}
catch( Exception ex )
{
this.warn("add entry written hander error:"+ex.Message, this.ToString());
}
}

///

1<summary>   
2/// 清除写日志时触发的外部方法   
3/// </summary>

public void clearEntryWrittenHander()
{
try
{
_entryWrittenEventHandler.Clear();
}
catch( Exception ex )
{
this.warn("clear entry written hander error:"+ex.Message, this.ToString());
}
}

///

1<summary>   
2/// 设置是否在写日志时触发的外部方法,默认为TRUE。   
3/// </summary>

///

1<param name="enabled"/>

是否
public void enableEntryWrittenHander( bool enabled )
{
_bEnableEntryWritten = enabled;
}

///

1<summary>   
2/// 将控制转给外部处理方法   
3/// </summary>

///

1<param name="source"/>

///

1<param name="e"/>

private void OnEntryWritten( string message, string source, enumLevel type)//object source, EntryWrittenEventArgs e)
{
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 );
}
}
}

///

1<summary>   
2/// 写事件日志   
3/// </summary>

///

1<param name="strMessage"/>

事件内容
///

1<param name="eventType"/>

事件类别,错误、警告或者消息
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);
}
}
}
}

4、CLoggerDatabase.cs

using System;
using System.IO;
using System.Diagnostics;
using System.Data;
using System.Data.OleDb;

namespace com.lenovo.zhangyuk.logger
{
///

1<summary>   
2/// 向数据库写日志   
3/// </summary>

class CLoggerDatabase : CLoggerAbstract
{
// 数据库连接
private static OleDbConnection _connection = null;
// 向数据库写日志的带参数的SQL串,通常是一条带参数的INSERT语句
private static string _updateStr = "";

///

1<summary>   
2/// 构造函数   
3/// </summary>

///

1<param name="strUpdate"/>

向数据库写日志的带参数的SQL串,通常是一条带参数的INSERT语句
///

1<param name="level"/>

日志输出的级别
public CLoggerDatabase( string strUpdate, enumLevel level ) : base(level)
{
if( null == _connection )
{
_connection = new OleDbConnection(CConfiguration.getConfiguration("database.connectionString"));
}
Trace.WriteLineIf( ( strUpdate.Length <=0 ), "error : update string is empty !" );
_updateStr = strUpdate;
}

///

1<summary>   
2/// 向数据库写日志   
3/// override抽象类的相应函数   
4/// </summary>

///

1<param name="message"/>

日志内容
///

1<param name="source"/>

日志源
///

1<param name="type"/>

日志级别
public override void _writeLog(string message, string source, enumLevel type)
{
try
{
OleDbCommand command = new OleDbCommand();
command.Connection = _connection;
command.CommandText = string.Format(_updateStr,
DateTime.Now.ToLocalTime(),
message,
source,
type.ToString());
command.CommandType = CommandType.Text;

_connection.Open();
command.ExecuteNonQuery();
_connection.Close();
}
catch( Exception ex )
{
_connection.Close();
throw ex;
}
}
}
}
5、CLoggerFile.cs

using System;
using System.IO;
using System.Diagnostics;

namespace com.lenovo.zhangyuk.logger
{
///

1<summary>   
2/// 向文件写日志   
3/// </summary>

class CLoggerFile : CLoggerAbstract
{
// 文件句柄
private static Stream _fileStream = null;

///

1<summary>   
2/// 构造函数   
3/// </summary>

///

1<param name="strFileName"/>

日志文件名
///

1<param name="level"/>

日志输出的级别
public CLoggerFile( string strFileName, enumLevel level ) : base(level)
{
Trace.WriteLineIf( ( strFileName.Length <=0 ), "error : logger file name is empty !" );

if( null == _fileStream )
{
_fileStream = new FileStream(strFileName, FileMode.OpenOrCreate, FileAccess.Write );
}
}

///

1<summary>   
2/// 向文件写日志   
3/// override抽象类的相应函数   
4/// </summary>

///

1<param name="message"/>

日志内容
///

1<param name="source"/>

日志源
///

1<param name="type"/>

日志级别
public override void _writeLog(string message, string source, enumLevel type)
{
try
{
_fileStream.Seek(0,SeekOrigin.End);
StreamWriter sw = new StreamWriter(_fileStream);
sw.WriteLine( DateTime.Now.ToString() + " " + type.ToString() + " " + source + " " + message);
sw.Flush();
}
catch( Exception ex )
{
throw ex;
}
}
}
}
6、CLoggerEvent.cs

using System;
using System.Diagnostics;

namespace com.lenovo.zhangyuk.logger
{
///

1<summary>   
2/// 向系统写入日志   
3/// </summary>

class CLoggerEvent : CLoggerAbstract
{
// 事件日志
private static EventLog _eventLog = new EventLog();
// 事件日志名
private static string _eventName = "com.lenovo.zhangyu";

///

1<summary>   
2/// 构造函数   
3/// </summary>

///

1<param name="strEventName"/>

事件日志名
///

1<param name="level"/>

日志输出的级别
public CLoggerEvent( string strEventName, enumLevel level ) : base(level)
{
_eventName = strEventName;
_eventLog.Log = _eventName;
_eventLog.EnableRaisingEvents = false;
}

///

1<summary>   
2/// 向系统写入日志   
3/// override抽象类的相应函数   
4/// </summary>

///

1<param name="message"/>

日志内容
///

1<param name="source"/>

日志源
///

1<param name="type"/>

日志级别
public override void _writeLog(string message, string source, enumLevel type)
{
try
{
if (!EventLog.SourceExists( source ))
{
EventLog.CreateEventSource( source,_eventName );
}
_eventLog.Source = source;
_eventLog.WriteEntry( message, myType2EventType( type ) );
}
catch( Exception ex )
{
throw ex;
}
}

///

1<summary>   
2/// 将自定义的日志级别转换为系统约定的日志级别   
3/// DEBUG INFO --&gt; Information   
4/// ERROR FATAL --&gt; Error   
5/// WARN --&gt; Warning   
6/// </summary>

///

1<param name="type"/>

自定义的日志级别
///

1<returns>系统约定的日志级别</returns>

private EventLogEntryType myType2EventType( enumLevel type )
{
EventLogEntryType eventType = EventLogEntryType.Information;
if( type == enumLevel.DEBUG || type == enumLevel.INFO )
eventType = EventLogEntryType.Information;
else if( type == enumLevel.ERROR || type == enumLevel.FATAL )
eventType = EventLogEntryType.Error;
else if( type == enumLevel.WARN )
eventType = EventLogEntryType.Warning;
return eventType;
}
}
}
7、CLoggerFactory.cs

using System;
using System.Collections;
using System.Reflection;

namespace com.lenovo.zhangyuk.logger
{
///

1<summary>   
2/// CLoggerFactory 的摘要说明。   
3/// </summary>

public class CLoggerFactory
{
private CLoggerFactory()
{
}

///

1<summary>   
2/// 根据配置文件中的设置创建日志类   
3/// </summary>

///

1<returns></returns>

public static ILogger getLogger()
{
// 日志类型
string logger = CConfiguration.getConfiguration("logger.type");
// 日志名或日志文件名
string loggerName = CConfiguration.getConfiguration("logger.name");
// 日志级别
enumLevel level = str2enum( CConfiguration.getConfiguration("logger.level") );

// 创建日志类
if( logger.ToLower().Equals("file") ) // 文件日志
{
return new CLoggerFile( loggerName, level );
}
else if( logger.ToLower().Equals("database") ) // 数据库日志
{
return new CLoggerDatabase( loggerName, level );
}
else// if( logger.ToLower().Equals("system") ) // 缺省使用系统日志
{
return new CLoggerEvent( loggerName, level );
}
}

///

1<summary>   
2/// 将string类型的日志输出级别转换成程序可识别的enum型   
3/// </summary>

///

1<param name="strLevel"/>

string类型的日志输出级别
///

1<returns>enumLevel类型的日志输出级别</returns>

private static enumLevel str2enum( string strLevel )
{
enumLevel level = 0;

if( strLevel.ToLower().Equals("debug") )
level = enumLevel.DEBUG;
else if( strLevel.ToLower().Equals("info") )
level = enumLevel.INFO;
else if( strLevel.ToLower().Equals("warn") )
level = enumLevel.WARN;
else if( strLevel.ToLower().Equals("error") )
level = enumLevel.ERROR;
else if( strLevel.ToLower().Equals("fatal") )
level = enumLevel.FATAL;
else
level = enumLevel.INFO;

return level;
}
}
}
8、

1<configuration>
2<appsettings>
3<add key="database.connectionString" value="Provider=OraOLEDB.Oracle.1;Password=zy;User ID=zy;Data Source=mytest"></add>
4<add key="logger.type" value="file"></add>
5<add key="logger.level" value="debug"></add>
6<add key="logger.name" value="c:\\\mylog.txt"></add>
7</appsettings>
8</configuration>

作者简介:张昱( [email protected]

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