C#开发高性能Log Help类设计开发

项目中要在操作数据库的异常处理中加入写Log日志,对于商业上有要求,写log时对其它操作尽可能影响小
首页 新闻资讯 行业资讯 C#开发高性能Log Help类设计开发

概述

项目中要在操作数据库的异常处理中加入写Log日志,对于商业上有要求,写log时对其它操作尽可能影响小,不能因为加入log导致耗时太多。

设计思想

在写入日志时利用Queue来管理,写日志有一个专门的backgroud线程来处理,如果没有日志要写,这个线程处于wait状态,这就有了线程的异步处理。

简单的实现方式

复制

//<summary>  //Write Log  //<summary>  public static void WriteLog(string logFile, string msg)  {      try     {          System.IO.StreamWriter sw = System.IO.File.AppendText(                  logPath + LogFilePrefix +" "+ logFile + " " +                  DateTime.Now.ToString("yyyyMMdd") + ".Log"             );          sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:  ") + msg);          sw.Close();      }      catch (Exception)      {                     throw;      }  }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

我们的设计图

image 

而后我们在AddLogMessage时semaphore.Release()就能唤醒wait中的log 线程。

代码设计

复制

/// <summary>  /// Author: spring yang  /// Create time:2012/3/30  /// Log Help class  /// </summary>  /// <remarks>High performance log class</remarks>  public class Log : IDisposable  {      //Log Message queue      private static Queue<LogMessage> _logMessages;       //log save directory      private static string _logDirectory;       //log write file state      private static bool _state;       //log type      private static LogType _logType;       //log life time sign      private static DateTime _timeSign;       //log file stream writer      private static StreamWriter _writer;       /// <summary>      /// Wait enqueue wirte log message semaphore will release      /// </summary>      private Semaphore _semaphore;       /// <summary>      /// Single instance      /// </summary>      private static Log _log;       /// <summary>      /// Gets a single instance      /// </summary>      public static Log LogInstance      {          get { return _log ?? (_log = new Log()); }      }       private object _lockObjeck;       /// <summary>      /// Initialize Log instance      /// </summary>      private void Initialize()      {          if (_logMessages == null)          {   _state = true;              string logPath = System.Configuration.ConfigurationManager.AppSettings["LogDirectory"];              _logDirectory = string.IsNullOrEmpty(logPath) ? ".\\log\\" : logPath;              if (!Directory.Exists(_logDirectory)) Directory.CreateDirectory(_logDirectory);              _logType = LogType.Daily;              _lockObjeck=new object();              _semaphore = new Semaphore(0, int.MaxValue, Constants.LogSemaphoreName);              _logMessages = new Queue<LogMessage>();              var thread = new Thread(Work) {IsBackground = true};              thread.Start();          }      }       /// <summary>      /// Create a log instance      /// </summary>      private Log()      {          Initialize();      }       /// <summary>      /// Log save name type,default is daily      /// </summary>      public LogType LogType      {          get { return _logType; }          set { _logType = value; }      }       /// <summary>      /// Write Log file  work method      /// </summary>      private void Work()      {          while (true)          {              //Determine log queue have record need wirte              if (_logMessages.Count > 0)              {                  FileWriteMessage();              }              else                 if (WaitLogMessage()) break;          }      }       /// <summary>      /// Write message to log file      /// </summary>      private void FileWriteMessage()      {          LogMessage logMessage=null;          lock (_lockObjeck)          {              if(_logMessages.Count>0)              logMessage = _logMessages.Dequeue();          }          if (logMessage != null)          {              FileWrite(logMessage);          }      }       /// <summary>      /// The thread wait a log message      /// </summary>      /// <returns>is close or not</returns>      private bool WaitLogMessage()      {          //determine log life time is true or false          if (_state)          {              WaitHandle.WaitAny(new WaitHandle[] { _semaphore }, -1, false);              return false;          }          FileClose();          return true;      }       /// <summary>      /// Gets file name by log type      /// </summary>      /// <returns>log file name</returns>      private string GetFilename()      {          DateTime now = DateTime.Now;          string format = "";          switch (_logType)          {              case LogType.Daily:                  _timeSign = new DateTime(now.Year, now.Month, now.Day);                  _timeSign = _timeSign.AddDays(1);                  format = "yyyyMMdd'.log'";                  break;              case LogType.Weekly:                  _timeSign = new DateTime(now.Year, now.Month, now.Day);                  _timeSign = _timeSign.AddDays(7);                  format = "yyyyMMdd'.log'";                  break;              case LogType.Monthly:                  _timeSign = new DateTime(now.Year, now.Month, 1);                  _timeSign = _timeSign.AddMonths(1);                  format = "yyyyMM'.log'";                  break;              case LogType.Annually:                  _timeSign = new DateTime(now.Year, 1, 1);                  _timeSign = _timeSign.AddYears(1);                  format = "yyyy'.log'";                  break;          }          return now.ToString(format);      }       /// <summary>      /// Write log file message      /// </summary>      /// <param name="msg"></param>      private void FileWrite(LogMessage msg)      {          try         {              if (_writer == null)              {                  FileOpen();              }              else             {                  //determine the log file is time sign                  if (DateTime.Now >= _timeSign)                  {                      FileClose();                      FileOpen();                  }                  _writer.WriteLine(Constants.LogMessageTime+msg.Datetime);                  _writer.WriteLine(Constants.LogMessageType+msg.Type);                  _writer.WriteLine(Constants.LogMessageContent+msg.Text);                  _writer.Flush();              }          }          catch (Exception e)          {              Console.Out.Write(e);          }      }       /// <summary>      /// Open log file write log message      /// </summary>      private void FileOpen()      {          _writer = new StreamWriter(Path.Combine(_logDirectory, GetFilename()), true, Encoding.UTF8);      }       /// <summary>      /// Close log file      /// </summary>      private void FileClose()      {          if (_writer != null)          {              _writer.Flush();              _writer.Close();              _writer.Dispose();              _writer = null;          }      }       /// <summary>      /// Enqueue a new log message and release a semaphore      /// </summary>      /// <param name="msg">Log message</param>      public void Write(LogMessage msg)      {          if (msg != null)          {              lock (_lockObjeck)              {                  _logMessages.Enqueue(msg);                  _semaphore.Release();              }          }      }       /// <summary>      /// Write message by message content and type      /// </summary>      /// <param name="text">log message</param>      /// <param name="type">message type</param>      public void Write(string text, MessageType type)      {          Write(new LogMessage(text, type));      }       /// <summary>      /// Write Message by datetime and message content and type      /// </summary>      /// <param name="dateTime">datetime</param>      /// <param name="text">message content</param>      /// <param name="type">message type</param>      public void Write(DateTime dateTime, string text, MessageType type)      {          Write(new LogMessage(dateTime, text, type));      }       /// <summary>      /// Write message ty exception and message type      /// </summary>      /// <param name="e">exception</param>      /// <param name="type">message type</param>      public void Write(Exception e, MessageType type)      {          Write(new LogMessage(e.Message, type));      }       #region IDisposable member       /// <summary>      /// Dispose log      /// </summary>      public void Dispose()      {          _state = false;      }       #endregion  }   /// <summary>  /// Log Type  /// </summary>  /// <remarks>Create log by daily or weekly or monthly or annually</remarks>  public enum LogType  {      /// <summary>      /// Create log by daily      /// </summary>      Daily,       /// <summary>      /// Create log by weekly      /// </summary>      Weekly,       /// <summary>      /// Create log by monthly      /// </summary>      Monthly,       /// <summary>      /// Create log by annually      /// </summary>      Annually  }   /// <summary>  /// Log Message Class  /// </summary>  public class LogMessage  {       /// <summary>      /// Create Log message instance      /// </summary>      public LogMessage()          : this("", MessageType.Unknown)      {      }       /// <summary>      /// Crete log message by message content and message type      /// </summary>      /// <param name="text">message content</param>      /// <param name="messageType">message type</param>      public LogMessage(string text, MessageType messageType)          : this(DateTime.Now, text, messageType)      {      }       /// <summary>      /// Create log message by datetime and message content and message type      /// </summary>      /// <param name="dateTime">date time </param>      /// <param name="text">message content</param>      /// <param name="messageType">message type</param>      public LogMessage(DateTime dateTime, string text, MessageType messageType)      {          Datetime = dateTime;          Type = messageType;          Text = text;      }       /// <summary>      /// Gets or sets datetime      /// </summary>      public DateTime Datetime { get; set; }       /// <summary>      /// Gets or sets message content      /// </summary>      public string Text { get; set; }       /// <summary>      /// Gets or sets message type      /// </summary>      public MessageType Type { get; set; }       /// <summary>      /// Get Message to string      /// </summary>      /// <returns></returns>      public new string ToString()      {          return Datetime.ToString(CultureInfo.InvariantCulture) + "\t" + Text + "\n";      }  }   /// <summary>  /// Log Message Type enum  /// </summary>  public enum MessageType  {      /// <summary>      /// unknown type      /// </summary>      Unknown,       /// <summary>      /// information type      /// </summary>      Information,       /// <summary>      /// warning type      /// </summary>      Warning,       /// <summary>      /// error type      /// </summary>      Error,       /// <summary>      /// success type      /// </summary>      Success  }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

  • 45.

  • 46.

  • 47.

  • 48.

  • 49.

  • 50.

  • 51.

  • 52.

  • 53.

  • 54.

  • 55.

  • 56.

  • 57.

  • 58.

  • 59.

  • 60.

  • 61.

  • 62.

  • 63.

  • 64.

  • 65.

  • 66.

  • 67.

  • 68.

  • 69.

  • 70.

  • 71.

  • 72.

  • 73.

  • 74.

  • 75.

  • 76.

  • 77.

  • 78.

  • 79.

  • 80.

  • 81.

  • 82.

  • 83.

  • 84.

  • 85.

  • 86.

  • 87.

  • 88.

  • 89.

  • 90.

  • 91.

  • 92.

  • 93.

  • 94.

  • 95.

  • 96.

  • 97.

  • 98.

  • 99.

  • 100.

  • 101.

  • 102.

  • 103.

  • 104.

  • 105.

  • 106.

  • 107.

  • 108.

  • 109.

  • 110.

  • 111.

  • 112.

  • 113.

  • 114.

  • 115.

  • 116.

  • 117.

  • 118.

  • 119.

  • 120.

  • 121.

  • 122.

  • 123.

  • 124.

  • 125.

  • 126.

  • 127.

  • 128.

  • 129.

  • 130.

  • 131.

  • 132.

  • 133.

  • 134.

  • 135.

  • 136.

  • 137.

  • 138.

  • 139.

  • 140.

  • 141.

  • 142.

  • 143.

  • 144.

  • 145.

  • 146.

  • 147.

  • 148.

  • 149.

  • 150.

  • 151.

  • 152.

  • 153.

  • 154.

  • 155.

  • 156.

  • 157.

  • 158.

  • 159.

  • 160.

  • 161.

  • 162.

  • 163.

  • 164.

  • 165.

  • 166.

  • 167.

  • 168.

  • 169.

  • 170.

  • 171.

  • 172.

  • 173.

  • 174.

  • 175.

  • 176.

  • 177.

  • 178.

  • 179.

  • 180.

  • 181.

  • 182.

  • 183.

  • 184.

  • 185.

  • 186.

  • 187.

  • 188.

  • 189.

  • 190.

  • 191.

  • 192.

  • 193.

  • 194.

  • 195.

  • 196.

  • 197.

  • 198.

  • 199.

  • 200.

  • 201.

  • 202.

  • 203.

  • 204.

  • 205.

  • 206.

  • 207.

  • 208.

  • 209.

  • 210.

  • 211.

  • 212.

  • 213.

  • 214.

  • 215.

  • 216.

  • 217.

  • 218.

  • 219.

  • 220.

  • 221.

  • 222.

  • 223.

  • 224.

  • 225.

  • 226.

  • 227.

  • 228.

  • 229.

  • 230.

  • 231.

  • 232.

  • 233.

  • 234.

  • 235.

  • 236.

  • 237.

  • 238.

  • 239.

  • 240.

  • 241.

  • 242.

  • 243.

  • 244.

  • 245.

  • 246.

  • 247.

  • 248.

  • 249.

  • 250.

  • 251.

  • 252.

  • 253.

  • 254.

  • 255.

  • 256.

  • 257.

  • 258.

  • 259.

  • 260.

  • 261.

  • 262.

  • 263.

  • 264.

  • 265.

  • 266.

  • 267.

  • 268.

  • 269.

  • 270.

  • 271.

  • 272.

  • 273.

  • 274.

  • 275.

  • 276.

  • 277.

  • 278.

  • 279.

  • 280.

  • 281.

  • 282.

  • 283.

  • 284.

  • 285.

  • 286.

  • 287.

  • 288.

  • 289.

  • 290.

  • 291.

  • 292.

  • 293.

  • 294.

  • 295.

  • 296.

  • 297.

  • 298.

  • 299.

  • 300.

  • 301.

  • 302.

  • 303.

  • 304.

  • 305.

  • 306.

  • 307.

  • 308.

  • 309.

  • 310.

  • 311.

  • 312.

  • 313.

  • 314.

  • 315.

  • 316.

  • 317.

  • 318.

  • 319.

  • 320.

  • 321.

  • 322.

  • 323.

  • 324.

  • 325.

  • 326.

  • 327.

  • 328.

  • 329.

  • 330.

  • 331.

  • 332.

  • 333.

  • 334.

  • 335.

  • 336.

  • 337.

  • 338.

  • 339.

  • 340.

  • 341.

  • 342.

  • 343.

  • 344.

  • 345.

  • 346.

  • 347.

  • 348.

  • 349.

  • 350.

  • 351.

  • 352.

  • 353.

  • 354.

  • 355.

  • 356.

  • 357.

  • 358.

  • 359.

  • 360.

  • 361.

  • 362.

  • 363.

  • 364.

  • 365.

  • 366.

  • 367.

  • 368.

  • 369.

  • 370.

  • 371.

  • 372.

  • 373.

  • 374.

  • 375.

  • 376.

  • 377.

  • 378.

  • 379.

  • 380.

  • 381.

  • 382.

  • 383.

  • 384.

  • 385.

  • 386.

  • 387.

  • 388.

  • 389.

  • 390.

  • 391.

  • 392.

  • 393.

  • 394.

  • 395.

  • 396.

  • 397.

  • 398.

  • 399.

Test Case:

复制

public static void TestLog()  {      Log.LogInstance.Write(  "Test Message",MessageType.Information);      Log.LogInstance.Write("one",MessageType.Error);      Log.LogInstance.Write("two", MessageType.Success);      Log.LogInstance.Write("three", MessageType.Warning);  }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

运行结果:

image

接受Mainz的建议,改了部分代码。

Mainz:http://www.cnblogs.com/Mainz/

原文链接:http://www.cnblogs.com/springyangwc/archive/2012/03/30/2425822.html

【编辑推荐】

  1. C#几个经常犯错误汇总

  2. 浅谈面向对象程序设计C#中的类

  3. 详解C#中不同类的类型

  4. 浅谈C#中标准Dispose模式的实现

  5. C#选择正确的集合进行编码

24    2012-03-31 11:25:48    C#