zoukankan      html  css  js  c++  java
  • step by step 之餐饮管理系统四(日志模块实现)

      三天前基本上把数据库表设计的文档写好,今天想到了一个问题,还要再加几个表,一个是log表,用来记录系统日志,另外再加几个字典表,一些需要配置的数据但又不好放在像xml文件里面的数据可以放在这些字典表里面。

      从今天开始就正式进入系统设计与编码了,详细设计文档等系统做好后再补充了,因为一开始全部写好不大现实,中间过程中会不断地去迭代。现在的想法是每个模块分别去实现,然后再分别记录下来。

      今天要写的是日志模块,因为在生产环境中,好的日志至于重要,系统运行时出现的任何问题可以通过日志记录下来,对于发现与解决问题非常有帮助。因为日志是一个相对比较通用的模块,所以先设计好如果写日志模块,之后再写通用类模块,再数据库访问层与用户自定义控件,然后再数据实体与业务处理层,最后再写用户表现层。

      因为此次不使用第二方控件,所以不考虑像log4net,微软enterprise中好的日志控件,但是看了它们的代码,总体思想都差不多,就是各种级别的日志信息应该以什么样的格式输出到哪种介质中,也就是输出源,像文本文件还是数据库,还是控制台,还是系统日志邮件等等。基于它们的思想,把构思记录下来:

    日志最主要的就是一个日志器与附加器,像log4net中可以定义多个日志器,一个日志器可以附加多个输出源,而日志仓库就是如何存储和管理日志器,过虑器如果过虑各种级别的日志,而layout就是如何显示输出的消息。

    1、输出源只包含文本文件,数据库,系统日志和邮件。

    2、日志级别分别为Fatal, Error, Warn, Info, Debug。

    还是拿代码为例子来讲吧,首先定义一个日志器接口与日志操作接口ILog,日志器得先有一个名字,它的方法就是一个Log和IsEnabledFor,ILog包含的方法如下,用过log4net等日志控件的应该很熟悉。

    日志器接口详细代码如下:

     public interface ILogger
        {
            /// <summary>
            /// Gets the name of the logger.
            /// </summary>
            string Name { get; }
    
            /// <summary>
            /// This generic form is intended to be used by wrappers.
            /// </summary>
            void Log(LogCategory level, object message, Exception exception);
    
            bool IsEnabledFor(LogCategory level);
        }

    然后再定义一个包装接口

       public interface ILoggerWrapper
        {
            ILogger Logger
            {
                get;
            }
        }

    定义ILog接口,最后调用的都是在这里定义的接口

     public interface ILog : ILoggerWrapper
        {
            void Debug(object message);
    
            void Debug(object message, Exception exception);
    
            void DebugFormat(string format, params object[] args);
    
            void Info(object message);
    
            void Info(object message, Exception exception);
    
            void InfoFormat(string format, params object[] args);
    
            void Warn(object message);
    
            void Warn(object message, Exception exception);
    
            void WarnFormat(string format, params object[] args);
    
            void Error(object message);
    
            void Error(object message, Exception exception);
    
            void ErrorFormat(string format, params object[] args);
    
            void Fatal(object message);
    
            void Fatal(object message, Exception exception);
    
            void FatalFormat(string format, params object[] args);
    
    
            bool IsDebugEnabled
            {
                get;
            }
    
            bool IsInfoEnabled
            {
                get;
            }
    
            bool IsErrorEnabled
            {
                get;
            }
    
            bool IsWarnEnabled
            {
                get;
            }
    
            bool IsFatalEnabled
            {
                get;
            }
        }

    日志器有了,可以附加器呢,也就是源出源,其实真正的任务都是委托这些具体的附加器去做的呢,为什么log4net那么强大,我想它的附加器如此之多也是一大原因吧,基本上我们能想到的它都想到了,我们没有想到的它也想到了,下面就定义的几个具体的附加器。

    附加器如何跟前面的说的日志器关联呢,20个附加器不可能都直接与日志器去关联吧,所以定义一个所有附加器要实现的接口IAppender.

     public  interface IAppender
        {
           string Name
           {
               get;
               set;
           }
    
           void Close();
    
           void DoAppender(LogCategory level, object message, Exception exception);
        }

    拿文本文件为例,日志的输出源就是文本文件,消息写到这个介质上,下面是一个基类,然后子类就是继承这个类实现Write方法去写日志信息:

      public class TextWriterAppender : TextWriter
        {
            private TextWriter m_writer;
    
            public TextWriter Writer
            {
                get { return m_writer; }
                set { m_writer = value; }
            }
    
            virtual public string Name
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    throw new NotImplementedException();
                }
            }
    
            #region Public Methods
    
            /// <summary>
            /// Closes the writer and releases any system resources associated with the writer
            /// </summary>
            /// <remarks>
            /// <para>
            /// </para>
            /// </remarks>
            override public void Close()
            {
                m_writer.Close();
            }
    
            /// <summary>
            /// Dispose this writer
            /// </summary>
            /// <param name="disposing">flag indicating if we are being disposed</param>
            /// <remarks>
            /// <para>
            /// Dispose this writer
            /// </para>
            /// </remarks>
            override protected void Dispose(bool disposing)
            {
                if (disposing)
                {
                    ((IDisposable)m_writer).Dispose();
                }
            }
    
            /// <summary>
            /// Flushes any buffered output
            /// </summary>
            /// <remarks>
            /// <para>
            /// Clears all buffers for the writer and causes any buffered data to be written 
            /// to the underlying device
            /// </para>
            /// </remarks>
            override public void Flush()
            {
                m_writer.Flush();
            }
    
            /// <summary>
            /// Writes a character to the wrapped TextWriter
            /// </summary>
            /// <param name="value">the value to write to the TextWriter</param>
            /// <remarks>
            /// <para>
            /// Writes a character to the wrapped TextWriter
            /// </para>
            /// </remarks>
            override public void Write(char value)
            {
                m_writer.Write(value);
            }
    
            /// <summary>
            /// Writes a character buffer to the wrapped TextWriter
            /// </summary>
            /// <param name="buffer">the data buffer</param>
            /// <param name="index">the start index</param>
            /// <param name="count">the number of characters to write</param>
            /// <remarks>
            /// <para>
            /// Writes a character buffer to the wrapped TextWriter
            /// </para>
            /// </remarks>
            override public void Write(char[] buffer, int index, int count)
            {
                m_writer.Write(buffer, index, count);
            }
    
            /// <summary>
            /// Writes a string to the wrapped TextWriter
            /// </summary>
            /// <param name="value">the value to write to the TextWriter</param>
            /// <remarks>
            /// <para>
            /// Writes a string to the wrapped TextWriter
            /// </para>
            /// </remarks>
            override public void Write(String value)
            {
                m_writer.Write(value);
            }
    
            public override Encoding Encoding
            {
                get { return m_writer.Encoding; }
            }
    
            #endregion
        }

    日志器与附加器都有了,怎么去连接它们了,最后我想还是用泛型比较灵活,定义如下:

      public class LogFactory<L, A> : ILog
            where L : ILogger, new()
            where A : IAppender, new()
        {
    
            virtual public void Debug(object message)
            {
    #if DEBUG
                Logger.Log(m_levelDebug, message, null);
    #endif
            }
    
            virtual public void Debug(object message, Exception exception)
            {
    #if DEBUG
                Logger.Log(m_levelDebug, message, exception);
    #endif
            }
    
            virtual public void DebugFormat(string format, params object[] args)
            {
    #if DEBUG
                if (IsDebugEnabled)
                {
                    Logger.Log(m_levelDebug, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null);
                }
    #endif
            }
    
            virtual public void Info(object message)
            {
                Logger.Log(LevelInfo, message, null);
            }
    
            virtual public void Info(object message, Exception exception)
            {
                Logger.Log(LevelInfo, message, exception);
            }
    
            virtual public void InfoFormat(string format, params object[] args)
            {
                if (IsInfoEnabled)
                {
                    Logger.Log(LevelInfo, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null);
                }
            }
    
            virtual public void Warn(object message)
            {
                Logger.Log(LevelWarn, message, null);
            }
    
            virtual public void Warn(object message, Exception exception)
            {
                Logger.Log(LevelWarn, message, exception);
            }
    
            virtual public void WarnFormat(string format, params object[] args)
            {
                if (IsWarnEnabled)
                {
                    Logger.Log(LevelWarn, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null);
                }
            }
    
            virtual public void Error(object message)
            {
                Logger.Log(LevelError, message, null);
            }
    
            virtual public void Error(object message, Exception exception)
            {
                Logger.Log(LevelError, message, exception);
            }
    
            virtual public void ErrorFormat(string format, params object[] args)
            {
                if (IsErrorEnabled)
                {
                    Logger.Log(LevelError, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null);
                }
            }
    
            virtual public void Fatal(object message)
            {
                Logger.Log(LevelFatal, message, null);
            }
    
            virtual public void Fatal(object message, Exception exception)
            {
                Logger.Log(LevelFatal, message, exception);
            }
    
            virtual public void FatalFormat(string format, params object[] args)
            {
                if (IsFatalEnabled)
                {
                    Logger.Log(LevelFatal, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null);
                }
            }
    
            virtual public bool IsDebugEnabled
            {
                get
                {
                    return Logger.IsEnabledFor(m_levelDebug);
                }
            }
    
            virtual public bool IsInfoEnabled
            {
                get
                {
                    return Logger.IsEnabledFor(m_levelInfo);
                }
            }
    
            virtual public bool IsErrorEnabled
            {
                get
                {
                    return Logger.IsEnabledFor(m_levelError);
                }
            }
    
            virtual public bool IsWarnEnabled
            {
                get
                {
                    return Logger.IsEnabledFor(m_levelWarn);
                }
            }
    
            virtual public bool IsFatalEnabled
            {
                get
                {
                    return Logger.IsEnabledFor(m_levelFatal);
                }
            }
    
            private LogCategory m_levelDebug;
    
            public LogCategory LevelDebug
            {
                get { return LogCategory.Debug; }
                set { m_levelDebug = LogCategory.Debug; }
            }
            private LogCategory m_levelInfo;
    
            public LogCategory LevelInfo
            {
                get { return LogCategory.Info; }
                set { m_levelInfo = LogCategory.Info; }
            }
            private LogCategory m_levelWarn;
    
            public LogCategory LevelWarn
            {
                get { return LogCategory.Warn; }
                set { m_levelWarn = LogCategory.Warn; }
            }
            private LogCategory m_levelError;
    
            public LogCategory LevelError
            {
                get { return LogCategory.Error; }
                set { m_levelError = LogCategory.Error; }
            }
            private LogCategory m_levelFatal;
    
            public LogCategory LevelFatal
            {
                get { return LogCategory.Fatal; }
                set { m_levelFatal = LogCategory.Fatal; }
            }
    
            public ILogger Logger
            {
                get { return new L(); }
            }
        }

    把上面的泛型类闭合一个日志类:

     public class LogBase<A> : LogFactory<LogBase<A>, A>, ILogger
            where A : IAppender, new()
        {
            private LogCategory m_logLevel;
            public string Name
            {
                get
                {
                    return "LogBase";
                }
            }
    
            private A m_instance;
    
            public A Instance
            {
                get
                {
                    if (m_instance == null)
                    {
                        m_instance = new A();
                    }
                    return m_instance;
                }
                set { m_instance = value; }
            }
    
            public void Log(LogCategory level, object message, Exception exception)
            {
                Instance.DoAppender(level, message, exception);
            }
    
            public bool IsEnabledFor(LogCategory level)
            {
                switch (level)
                {
                    case LogCategory.Fatal:
                        LevelFatal = LogCategory.Fatal;
                        break;
                    case LogCategory.Error:
                        LevelError = LogCategory.Error;
                        break;
                    case LogCategory.Warn:
                        LevelWarn = LogCategory.Warn;
                        break;
                    case LogCategory.Debug:
                        LevelDebug = LogCategory.Debug;
                        break;
                    case LogCategory.Info:
                        LevelInfo = LogCategory.Info;
                        break;
                    default:
                        m_logLevel = LogCategory.Info;
                        break;
                }
    
                return true;
            }
        }

    再关闭一个泛型参数:

      public class TxtFileLog :  LogBase<TxtFileLog>, IAppender
        {
            private string m_name;
            private FileLogWriter m_writer;
    
            public TxtFileLog()
            {
                if (m_writer == null)
                {
                    m_writer = new FileLogWriter();
                }
            }
    
            public FileLogWriter Writer
            {
                get { return m_writer; }
                set { m_writer = value; }
            }
    
            public new string Name
            {
                get
                {
                    return m_name;
                }
                set
                {
                    m_name = value;
                }
            }
    
            public void Close()
            {
                m_writer.Close();
            }
    
            public void DoAppender(LogCategory level, object message, Exception exception)
            {
                m_writer.Write(Convert.ToString(message), level, (LogMessage)exception);
            }

    上面的类实现了日志器与附加器的连接,然后就可以去客户端验证好不好用了:

                ILog log = new TxtFileLog();
                log.Debug("Are you OK??");

    打印如下信息:

    这只是第一步,后面还得写数据库与邮件附加器的输出方法。写一个好的日志器还真不容易。之后会把一些可以配置的东西放到配置文件里面,

    接下来就写通用类与数据库访问层。

    注:需要完整源码的可以mark下,无偿发到你邮箱

  • 相关阅读:
    WINDOWS 修改ROUTE命令
    SQL Server 索引 之 书签查找 <第十一篇>
    SQL Server索引的维护
    SQL Server索引语法 <第四篇>
    SQL Server索引 (原理、存储)聚集索引、非聚集索引、堆 <第一篇>
    SQL Server
    开发反模式
    开发反模式(GUID)
    开发反模式
    SQLServer 窗口函数
  • 原文地址:https://www.cnblogs.com/cang/p/4230353.html
Copyright © 2011-2022 走看看