当前位置: 代码迷 >> C# >> step by step 之饮食管理系统四(日志模块实现)
  详细解决方案

step by step 之饮食管理系统四(日志模块实现)

热度:373   发布时间:2016-05-05 05:10:32.0
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下,无偿发到你邮箱

21楼DataCool
还以为博主只是随便写写,我对餐饮行业的需求比较熟,也可以提供成品软件给你参考。欢迎共同探讨。
Re: cang2012
@DataCool,好的,谢谢
20楼系统工程
错了上面邮箱是 [email protected]
Re: cang2012
@系统工程,好的,我代码补充好后一起发你们
19楼gc_Joey
[email protected]
Re: cang2012
@gc_Joey,好的,我代码补充好后一起发你们
18楼GavinJun
一直关注楼主,[email protected] 谢谢
Re: cang2012
@GavinJun,@andyshao,@潇湘〃细雨,@Sunday*,好的,我代码补充好后一起发你们
Re: cang2012
@GavinJun,@浪子丁,好的,我代码补充好后一起发你们
17楼梵哥
[email protected],谢谢楼主
16楼师太你就从了老衲吧
[email protected]!感谢
15楼潇湘〃细雨
mark,[email protected]
14楼沈赟
Thanks!
Re: cang2012
@沈赟,you are welcome
13楼未来帅哥
[email protected],,如果能直接有一个演示地址就更好了!
12楼darknoll
[email protected],,Thanks!
11楼上帝之城
[email protected]
10楼丁勇
mark [email protected]
9楼Nature.j
[email protected] 来一份吧,楼主,谢谢。
Re: cang2012
@Nature.j,好的,不用谢
8楼wipphj
[email protected],谢谢
7楼Sunday*
[email protected] 学习下,谢谢!
Re: cang2012
@Sunday*,好的,我代码补充好后一起发你们
6楼andyshao
[email protected]!感谢
Re: cang2012
@andyshao,好的,我代码补充好后一起发你们
5楼wp8733684
[email protected];谢谢
4楼DownUp
[email protected]
Re: cang2012
@DownUp,好的,我代码补充好后一起发你们
3楼系统工程
[email protected] 谢谢,源码研究研究
2楼锥生零
[email protected] 楼主好人 谢谢啦
1楼浪子丁
mark [email protected] thanks
  相关解决方案