在你的 .NET 程序中经常会记录一些日志或者错误,为了实现这个功能,你可能会使用市面上那些现成的日志框架(log4net,nlog ...),当然你也可以设计并开发一个自己的日志框架,在这篇文章中,我将会带你一起如何轻松愉快的创建一个自定义日志框架,并且一步一步的构建这个简单的 logger。
首先,你要知道什么叫 log targets,从字面意思看就是你的日志要输送到哪里?可以假定我们的日志可以输出到: 文件,数据库 或者 windows 日志 中,下面我在 日志框架 中定义一个枚举表示这三个输出地。
public enum LogTarget
{
File, Database, EventLog
}
接下来实现一下 logger 类,我准备定义三个类来表示这三个output,FileLogger
, DBLogger
, EventLog
,所有的这些类都需要继承基类 LogBase,下面上一下代码展示一下这些类的继承关系。
public abstract class LogBase
{
public abstract void Log(string message);
}
public class FileLogger : LogBase
{
public string filePath = @”D:IDGLog.txt”;
public override void Log(string message)
{
using (StreamWriter streamWriter = new StreamWriter(filePath))
{
streamWriter.WriteLine(message);
streamWriter.Close();
}
}
}
public class DBLogger : LogBase
{
string connectionString = string.Empty;
public override void Log(string message)
{
//Code to log data to the database
}
}
public class EventLogger: LogBase
{
public override void Log(string message)
{
EventLog eventLog = new EventLog(“”);
eventLog.Source ="IDGEventLog";
eventLog.WriteEntry(message);
}
}
上面 DBLogger 的 Log 方法我故意没有实现,你可以在学习完本文后自己来实现这一块的逻辑,将日志记录到数据库中。
正如你看到的,上面三个类:FileLogger
,EventLog
和 DBLogger
继承了抽象类 LogBase,这个抽象类定义了一个抽象方法 Log(), 这个 Log() 方法中定义了一个 string 类型的参数,这个参数的内容将会被记录到 file 或者 database 或者 windows event 中。
现在我们一起来构建一个 LogHelper 类,这个类可以用简单工厂模式,根据参数的不同创建不同的 XXXLogger 子类,用简单工厂简化我们调用其中各个子类的 Log() 方法,下面展示了具体代码:
public static class LogHelper
{
private static LogBase logger = null;
public static void Log(LogTarget target, string message)
{
switch(target)
{
case LogTarget.File:
logger = new FileLogger();
logger.Log(message);
break;
case LogTarget.Database:
logger = new DBLogger();
logger.Log(message);
break;
case LogTarget.EventLog:
logger = new EventLogger();
logger.Log(message);
break;
default:
return;
}
}
}
LogHelper 类的 Log() 方法接收一个 string 参数和一个 LogTarget 枚举实例,然后使用 switch: case
结构去决定记录日志的 target 是哪一个。
我去,我忘了使用同步机制对这些子类的 log() 方法的调用,现在赶紧同步一下,我可以使用 C# 中的 lock 关键词 在 各个子类的 log 方法的合适地方使用,可以参考下面代码的 LogBase 类,我在这个类中定义了一个 protected 类型的 lockObj 对象,这个对象会被所有子类中的 Log 方法所使用,下面就是这个类的修改版本:
public abstract class LogBase
{
protected readonly object lockObj = new object();
public abstract void Log(string message);
}
public class FileLogger : LogBase
{
public string filePath = @”D:IDGLog.txt”;
public override void Log(string message)
{
lock (lockObj)
{
using (StreamWriter streamWriter = new StreamWriter(filePath))
{
streamWriter.WriteLine(message);
streamWriter.Close();
}
}
}
}
public class EventLogger : LogBase
{
public override void Log(string message)
{
lock (lockObj)
{
EventLog m_EventLog = new EventLog(“”);
m_EventLog.Source ="IDGEventLog";
m_EventLog.WriteEntry(message);
}
}
}
public class DBLogger : LogBase
{
string connectionString = string.Empty;
public override void Log(string message)
{
lock (lockObj)
{
//Code to log data to the database
}
}
}
现在你可以调用 LogHelper.Log 方法了,指定一个 LogTarget 枚举参数和一个需要记录到日志的文本,如下代码所示:
class Program
{
static void Main(string[] args)
{
LogHelper.Log(LogTarget.File, “Hello”);
}
}
如果你需要切换日志的记录方式,实现起来很简单,在 LogHelper.Log 方法中传递一个不同的 LogTarget 参数即可。
这个框架做的非常简单,还有太多需要实现的功能去完善这个 logger framework,比如说,你可以加入 异步 和 队列,以便应对有大量的 message 被灌入,因为有了异步,logger 在写入日志的时候不会被当前线程阻塞,同样,你也可以实现一些 message 的级别,比如说 info,warning,error 等等。