译文链接: https://www.infoworld.com/article/2980677/implement-a-simple-logger-in-csharp.html

在你的 .NET 程序中经常会记录一些日志或者错误,为了实现这个功能,你可能会使用市面上那些现成的日志框架(log4net,nlog ...),当然你也可以设计并开发一个自己的日志框架,在这篇文章中,我将会带你一起如何轻松愉快的创建一个自定义日志框架,并且一步一步的构建这个简单的 logger。

首先,你要知道什么叫 log targets,从字面意思看就是你的日志要输送到哪里?可以假定我们的日志可以输出到: 文件,数据库 或者 windows 日志 中,下面我在 日志框架 中定义一个枚举表示这三个输出地。

public enum LogTarget
    {
        File, Database, EventLog
    }

构建 logger 类

接下来实现一下 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,EventLogDBLogger 继承了抽象类 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 等等。

更多高质量干货:参见我的 GitHub: dotnetfly