用 C# 实现一个简单的日志框架

在你的 .NET 程序中经常会记录一些日志或者错误,为了实现这个功能,你可能会使用市面上那些现成的日志框架(log4net,nlog ...),当然你也可以设计并开发一个自己的日志框架,在这篇文章中,我将会带你一起如何轻松愉快的创建一个自定义日志框架,并且一步一步的构建这个简单的 logger 。
首先,你要知道什么叫 log targets,从字面意思看就是你的日志要输送到哪里?可以假定我们的日志可以输出到: 文件,数据库 或者 windows 日志 中,下面我在 日志框架 中定义一个枚举表示这三个输出地 。
public enum LogTarget{File, Database, EventLog}构建 logger 类接下来实现一下 logger 类,我准备定义三个类来表示这三个output,FileLoggerDBLoggerEventLog ,所有的这些类都需要继承基类 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 类现在我们一起来构建一个 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 方法的同步调用我去,我忘了使用同步机制对这些子类的 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 等等 。


推荐阅读