程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> step by step 之餐飲管理系統四(日志模塊實現),step餐飲管理系統

step by step 之餐飲管理系統四(日志模塊實現),step餐飲管理系統

編輯:C#入門知識

step by step 之餐飲管理系統四(日志模塊實現),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下,無償發到你郵箱

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved