首页 > 技术文章 > 自己动手丰衣足食 ,C#框架系列----- 日志框架

dongqinnanren 2016-10-15 16:26 原文

工作快三年,入园子差不多有三年了,每天茶余饭后,轻敲鼠标偷偷的打开博客园,肆无忌惮的品尝着各种干货,慢慢的从新人变成了老司机,从软香蕉变成了硬橡胶,一篇篇优质的博客让我陶醉其中无法自拔,俗话说三年之痛,七年之痒,在这个我认为不痛不痒的时候,是时候奉献一下自己的积累,开始准备一个简单框架系列主要包括----日志,基于HTTP传输,Windows内部消息通讯,面向对象容器包装等,目前只总结了这么多,我们就废话少数开始第一个框架。

 

首先做一下简单的需求分析,常见的日志功能需求:

1. 按日期类型记录(天、周、月、年)

2. 按文件大小记录(行数或字节)

3. 按日志等级记录(Unknow、Error、Warning、Info、Debug)

4. 定时清理日志(依据实际大小制定具体天数)

5. 为方便开发调试,针对服务类型开发,同时显示在Console界面(继承TraceListener)

6. 支持多线程同时日志记录

 

框架准备:轻量级日志框架,我给它起了个名字,就叫做LogLight

枚举类型:

 1 public enum EnumLogType
 2     {
 3         Daily,
 4         Weekly,
 5         Monthly,
 6         Annually
 7     }
 8 
 9     public enum EunmMsgType
10     {
11         Unknown,
12         Error,
13         Warning,
14         Info,
15         Debug
16     }

每行内容对象,重写ToString方法,重载构造函数

 1  public class LogMsg
 2     {
 3         public LogMsg(string text, string category)
 4         {
 5             Category = category;
 6             DateTime = DateTime.Now;
 7             Text = text;
 8             Type = EunmMsgType.Unknown;
 9         }
10 
11         public LogMsg(string text, EunmMsgType type)
12         {
13             Category = "";
14             DateTime = DateTime.Now;
15             Text = text;
16             Type = type;
17         }
18 
19         public LogMsg(DateTime dt, string text, EunmMsgType type)
20         {
21             Category = "";
22             DateTime = dt;
23             Text = text;
24             Type = type;
25         }
26 
27         public string Text { get; set; }
28 
29         public DateTime DateTime { get; set; }
30 
31         public string Category { get; set; }
32 
33         public EunmMsgType Type { get; set; }
34 
35         public override string ToString()
36         {
37             var bulider = new StringBuilder();
38             bulider.Append(DateTime.ToString("yyyy-MM-dd HH:mm:ss:ff"));
39             bulider.Append(Category);
40             bulider.Append(" ");
41             bulider.Append(Text);
42             return bulider.ToString();
43         }
44     }

程序入口

 1 public class LogLightConsole
 2     {
 3         public static EunmMsgType LogLevel = EunmMsgType.Debug;
 4 
 5         public static void WriteLog(string sInfo, EunmMsgType type)
 6         {
 7             if (type <= LogLevel)
 8             {
 9                 Trace.WriteLine(new LogMsg(sInfo, type));
10             }
11         }
12     }

根据设定条件创建文件,定义文件行条数,定期删除文件,支持多线程操作,防止同时访问队列造成的死锁

  1  public class Logger : IDisposable
  2     {
  3         private static readonly int _keepLogDayCount = 15;
  4 
  5         private static int _lineCount;
  6 
  7         private static readonly int _lineMaxCount = 0x3d090;//2500
  8 
  9         private static Queue<LogMsg> _msgs;
 10 
 11         private static string _path;
 12 
 13         private static bool _state;
 14 
 15         private static DateTime _timeSign;
 16 
 17         private static EnumLogType _type;
 18 
 19         private static StreamWriter _writer;
 20 
 21         private readonly bool _bOutputCount = false;
 22 
 23         private readonly string _format = "yyyy-MM-dd HH:mm:ss:fff";
 24 
 25         private long _count;
 26 
 27         public Logger(string path, EnumLogType type)
 28         {
 29             if (_msgs == null)
 30             {
 31                 _state = true;
 32                 _path = path;
 33                 _type = type;
 34                 _msgs = new Queue<LogMsg>();
 35                 var thread = new Thread(Work) {IsBackground = true};
 36                 thread.Start();
 37             }
 38         }
 39 
 40         public void Dispose()
 41         {
 42             _state = false;
 43         }
 44 
 45         private void FileClose()
 46         {
 47             if (_writer == null) return;
 48             _writer.Flush();
 49             _writer.Close();
 50             _writer.Dispose();
 51             _writer = null;
 52         }
 53 
 54         private void FileOpen()
 55         {
 56             _lineCount = 0;
 57             _writer = new StreamWriter(GetFileName(), true, Encoding.UTF8);
 58         }
 59 
 60         private void FileWrite(LogMsg msg)
 61         {
 62             try
 63             {
 64                 if (_writer == null)
 65                 {
 66                     FileOpen();
 67                 }
 68 
 69                 if (_writer != null)
 70                 {
 71                     if ((DateTime.Now >= _timeSign) || _lineCount > _lineMaxCount)
 72                     {
 73                         FileClose();
 74                         try
 75                         {
 76                             var fileSn = 0;
 77                             for (var str = _path + GetFilenameBeforeDays(0, _keepLogDayCount);
 78                                 File.Exists(str);
 79                                 str = _path + GetFilenameBeforeDays(fileSn, _keepLogDayCount))
 80                             {
 81                                 File.Delete(str);
 82                                 fileSn++;
 83                             }
 84                         }
 85                         catch (Exception exception)
 86                         {
 87                             Console.Out.Write(exception);
 88                         }
 89                         FileOpen();
 90                     }
 91                     _lineCount++;
 92                     _writer.Write(msg.DateTime.ToString(_format));
 93                     _writer.Write(' ');
 94                     if (msg.Type == EunmMsgType.Unknown)
 95                     {
 96                         _writer.Write(msg.Category);
 97                     }
 98                     else
 99                     {
100                         _writer.Write(msg.Type);
101                     }
102                     _writer.Write(' ');
103                     _writer.WriteLine(msg.Text);
104                     _writer.Flush();
105                 }
106             }
107             catch (Exception exception)
108             {
109                 Console.Out.Write(exception);
110             }
111         }
112 
113         private string GetFileName()
114         {
115             var num = 0;
116             var now = DateTime.Now;
117             var format = "";
118 
119             Label_OO0E:
120             switch (_type)
121             {
122                 case EnumLogType.Daily:
123                     _timeSign = new DateTime(now.Year, now.Month, now.Day);
124                     _timeSign = _timeSign.AddDays(1.0);
125                     format = "yyyyMMdd";
126                     break;
127                 case EnumLogType.Weekly:
128                     _timeSign = new DateTime(now.Year, now.Month, now.Day);
129                     _timeSign = _timeSign.AddDays(7.0);
130                     format = "yyyyMMdd";
131                     break;
132                 case EnumLogType.Monthly:
133                     _timeSign = new DateTime(now.Year, now.Month, 1);
134                     _timeSign = _timeSign.AddMonths(1);
135                     format = "yyyyMM";
136                     break;
137                 case EnumLogType.Annually:
138                     _timeSign = new DateTime(now.Year, 1, 1);
139                     _timeSign = _timeSign.AddYears(1);
140                     format = "yyyy";
141                     break;
142             }
143             if (File.Exists(_path + now.ToString(format) + string.Format("-{0}.log", num)))
144             {
145                 num++;
146                 goto Label_OO0E;
147             }
148             return _path + now.ToString(format) + string.Format("-{0}.log", num);
149         }
150 
151         private string GetFilenameBeforeDays(int fileSn, int dayCount)
152         {
153             var time = DateTime.Now - TimeSpan.FromDays(dayCount);
154             var format = "";
155             switch (_type)
156             {
157                 case EnumLogType.Daily:
158                     format = "yyyyMMdd";
159                     break;
160                 case EnumLogType.Weekly:
161                     format = "yyyyMMdd";
162                     break;
163                 case EnumLogType.Monthly:
164                     format = "yyyyMM";
165                     break;
166                 case EnumLogType.Annually:
167                     format = "yyyy";
168                     break;
169             }
170             return time.ToString(format) + string.Format("-{0}.log", fileSn);
171         }
172 
173         private void Work()
174         {
175             Label_0000:
176             while (_msgs.Count > 0)
177             {
178                 LogMsg msg = null;
179                 lock (_msgs)
180                 {
181                     if (_msgs.Count > 0)
182                     {
183                         msg = _msgs.Dequeue();
184                         _count -= 1L;
185                     }
186 
187                     if (msg != null)
188                     {
189                         if (_bOutputCount)
190                         {
191                             msg.Text = msg.Text + string.Format("{0}", _count);
192                         }
193                         FileWrite(msg);
194                     }
195                 }
196             }
197 
198             if (_state)
199             {
200                 Thread.Sleep(1);
201                 goto Label_0000;
202             }
203             FileClose();
204         }
205 
206         public void Write(LogMsg msg)
207         {
208             if (msg != null)
209             {
210                 lock (_msgs)
211                 {
212                     _count += 1L;
213                     _msgs.Enqueue(msg);
214                 }
215             }
216         }
217 
218         public void Write(string text, EunmMsgType type)
219         {
220             Write(new LogMsg(text, type));
221         }
222 
223         public void Write(string text, string category)
224         {
225             Write(new LogMsg(text, category));
226         }
227     }

初始化框架类,调用TraceLinster监听日志输入,重写WriteLine方法(非常重要)--->调用logger写方法

public class LogConsole : TraceListener
    {
        public static readonly LogConsole InstanceLogConsole = new LogConsole();
        private Logger _logger;

        public void Init(bool UserDebugOutput, bool UseCrForWriteLine, string sPath)
        {
            if (!Directory.Exists(sPath))
            {
                Directory.CreateDirectory(sPath);
            }
            _logger = new Logger(sPath, EnumLogType.Daily);
            if (UserDebugOutput)
            {
                Debug.Listeners.Add(this);
            }
            else
            {
                Trace.Listeners.Add(this);
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && (_logger != null))
            {
                _logger.Dispose();
                _logger = null;
            }
        }

        public override void WriteLine(object o)
        {
            var logMsg = o as LogMsg;
            if (logMsg != null)
            {
                var msg = logMsg;
                if (_logger != null)
                {
                    _logger.Write(msg);
                }
                Console.WriteLine(msg.ToString());
            }
        }

        public override void WriteLine(string message, string category)
        {
            if (_logger != null)
            {
                _logger.Write(message, category);
            }
        }


        public override void WriteLine(string message)
        {
            if (_logger != null)
            {
                _logger.Write(message, EunmMsgType.Info);
            }
        }

        public override void Write(string message)
        {
            if (_logger != null)
            {
                _logger.Write(message, EunmMsgType.Info);
            }
        }
    }

测试代码:

class Program
    {
       static  void Main(string[] args)
        {
            var path = AppDomain.CurrentDomain.BaseDirectory + "Log\\";

            LogConsole.InstanceLogConsole.Init(true,true,path);

             Test test = new Test();
             test.Work();
            Console.ReadLine();
        }      
    }

    public class Test
    {
       public  void Work()
        {
            for (int i = 0; i < 100; i++)
            {
                ThreadPool.QueueUserWorkItem(Go, i.ToString());
            }

        }

        private void Go(object state)
        {
            LogLightConsole.WriteLog(state.ToString(), EunmMsgType.Info);
        }
    }

希望可以帮到大家,如果你喜欢或者感觉还可以点个赞给作者点动力,如果转载请注明连接。http://www.cnblogs.com/dongqinnanren/p/5964686.html

推荐阅读