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

开发 后端
项目中要在操作数据库的异常处理中加入写Log日志,对于商业上有要求,写log时对其它操作尽可能影响小,不能因为加入log导致耗时太多。在写入日志时利用Queue来管理,写日志有一个专门的backgroud线程来处理,如果没有日志要写,这个线程处于wait状态,这就有了线程的异步处理。

概述

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

设计思想

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

简单的实现方式

  1. //<summary>  
  2. //Write Log  
  3. //<summary>  
  4. public static void WriteLog(string logFile, string msg)  
  5. {  
  6.     try 
  7.     {  
  8.         System.IO.StreamWriter sw = System.IO.File.AppendText(  
  9.                 logPath + LogFilePrefix +" "+ logFile + " " +  
  10.                 DateTime.Now.ToString("yyyyMMdd") + ".Log" 
  11.             );  
  12.         sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:  ") + msg);  
  13.         sw.Close();  
  14.     }  
  15.     catch (Exception)  
  16.     {  
  17.            
  18.         throw;  
  19.     }  

我们的设计图

image 

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

代码设计

  1. /// <summary>  
  2. /// Author: spring yang  
  3. /// Create time:2012/3/30  
  4. /// Log Help class  
  5. /// </summary>  
  6. /// <remarks>High performance log class</remarks>  
  7. public class Log : IDisposable  
  8. {  
  9.     //Log Message queue  
  10.     private static Queue<LogMessage> _logMessages;  
  11.  
  12.     //log save directory  
  13.     private static string _logDirectory;  
  14.  
  15.     //log write file state  
  16.     private static bool _state;  
  17.  
  18.     //log type  
  19.     private static LogType _logType;  
  20.  
  21.     //log life time sign  
  22.     private static DateTime _timeSign;  
  23.  
  24.     //log file stream writer  
  25.     private static StreamWriter _writer;  
  26.  
  27.     /// <summary>  
  28.     /// Wait enqueue wirte log message semaphore will release  
  29.     /// </summary>  
  30.     private Semaphore _semaphore;  
  31.  
  32.     /// <summary>  
  33.     /// Single instance  
  34.     /// </summary>  
  35.     private static Log _log;  
  36.  
  37.     /// <summary>  
  38.     /// Gets a single instance  
  39.     /// </summary>  
  40.     public static Log LogInstance  
  41.     {  
  42.         get { return _log ?? (_log = new Log()); }  
  43.     }  
  44.  
  45.     private object _lockObjeck;  
  46.  
  47.     /// <summary>  
  48.     /// Initialize Log instance  
  49.     /// </summary>  
  50.     private void Initialize()  
  51.     {  
  52.         if (_logMessages == null)  
  53.         {   _state = true;  
  54.             string logPath = System.Configuration.ConfigurationManager.AppSettings["LogDirectory"];  
  55.             _logDirectory = string.IsNullOrEmpty(logPath) ? ".\\log\\" : logPath;  
  56.             if (!Directory.Exists(_logDirectory)) Directory.CreateDirectory(_logDirectory);  
  57.             _logType = LogType.Daily;  
  58.             _lockObjeck=new object();  
  59.             _semaphore = new Semaphore(0, int.MaxValue, Constants.LogSemaphoreName);  
  60.             _logMessages = new Queue<LogMessage>();  
  61.             var thread = new Thread(Work) {IsBackground = true};  
  62.             thread.Start();  
  63.         }  
  64.     }  
  65.  
  66.     /// <summary>  
  67.     /// Create a log instance  
  68.     /// </summary>  
  69.     private Log()  
  70.     {  
  71.         Initialize();  
  72.     }  
  73.  
  74.     /// <summary>  
  75.     /// Log save name type,default is daily  
  76.     /// </summary>  
  77.     public LogType LogType  
  78.     {  
  79.         get { return _logType; }  
  80.         set { _logType = value; }  
  81.     }  
  82.  
  83.     /// <summary>  
  84.     /// Write Log file  work method  
  85.     /// </summary>  
  86.     private void Work()  
  87.     {  
  88.         while (true)  
  89.         {  
  90.             //Determine log queue have record need wirte  
  91.             if (_logMessages.Count > 0)  
  92.             {  
  93.                 FileWriteMessage();  
  94.             }  
  95.             else 
  96.                 if (WaitLogMessage()) break;  
  97.         }  
  98.     }  
  99.  
  100.     /// <summary>  
  101.     /// Write message to log file  
  102.     /// </summary>  
  103.     private void FileWriteMessage()  
  104.     {  
  105.         LogMessage logMessage=null;  
  106.         lock (_lockObjeck)  
  107.         {  
  108.             if(_logMessages.Count>0)  
  109.             logMessage = _logMessages.Dequeue();  
  110.         }  
  111.         if (logMessage != null)  
  112.         {  
  113.             FileWrite(logMessage);  
  114.         }  
  115.     }  
  116.  
  117.     /// <summary>  
  118.     /// The thread wait a log message  
  119.     /// </summary>  
  120.     /// <returns>is close or not</returns>  
  121.     private bool WaitLogMessage()  
  122.     {  
  123.         //determine log life time is true or false  
  124.         if (_state)  
  125.         {  
  126.             WaitHandle.WaitAny(new WaitHandle[] { _semaphore }, -1, false);  
  127.             return false;  
  128.         }  
  129.         FileClose();  
  130.         return true;  
  131.     }  
  132.  
  133.     /// <summary>  
  134.     /// Gets file name by log type  
  135.     /// </summary>  
  136.     /// <returns>log file name</returns>  
  137.     private string GetFilename()  
  138.     {  
  139.         DateTime now = DateTime.Now;  
  140.         string format = "";  
  141.         switch (_logType)  
  142.         {  
  143.             case LogType.Daily:  
  144.                 _timeSign = new DateTime(now.Year, now.Month, now.Day);  
  145.                 _timeSign = _timeSign.AddDays(1);  
  146.                 format = "yyyyMMdd'.log'";  
  147.                 break;  
  148.             case LogType.Weekly:  
  149.                 _timeSign = new DateTime(now.Year, now.Month, now.Day);  
  150.                 _timeSign = _timeSign.AddDays(7);  
  151.                 format = "yyyyMMdd'.log'";  
  152.                 break;  
  153.             case LogType.Monthly:  
  154.                 _timeSign = new DateTime(now.Year, now.Month, 1);  
  155.                 _timeSign = _timeSign.AddMonths(1);  
  156.                 format = "yyyyMM'.log'";  
  157.                 break;  
  158.             case LogType.Annually:  
  159.                 _timeSign = new DateTime(now.Year, 1, 1);  
  160.                 _timeSign = _timeSign.AddYears(1);  
  161.                 format = "yyyy'.log'";  
  162.                 break;  
  163.         }  
  164.         return now.ToString(format);  
  165.     }  
  166.  
  167.     /// <summary>  
  168.     /// Write log file message  
  169.     /// </summary>  
  170.     /// <param name="msg"></param>  
  171.     private void FileWrite(LogMessage msg)  
  172.     {  
  173.         try 
  174.         {  
  175.             if (_writer == null)  
  176.             {  
  177.                 FileOpen();  
  178.             }  
  179.             else 
  180.             {  
  181.                 //determine the log file is time sign  
  182.                 if (DateTime.Now >= _timeSign)  
  183.                 {  
  184.                     FileClose();  
  185.                     FileOpen();  
  186.                 }  
  187.                 _writer.WriteLine(Constants.LogMessageTime+msg.Datetime);  
  188.                 _writer.WriteLine(Constants.LogMessageType+msg.Type);  
  189.                 _writer.WriteLine(Constants.LogMessageContent+msg.Text);  
  190.                 _writer.Flush();  
  191.             }  
  192.         }  
  193.         catch (Exception e)  
  194.         {  
  195.             Console.Out.Write(e);  
  196.         }  
  197.     }  
  198.  
  199.     /// <summary>  
  200.     /// Open log file write log message  
  201.     /// </summary>  
  202.     private void FileOpen()  
  203.     {  
  204.         _writer = new StreamWriter(Path.Combine(_logDirectory, GetFilename()), true, Encoding.UTF8);  
  205.     }  
  206.  
  207.     /// <summary>  
  208.     /// Close log file  
  209.     /// </summary>  
  210.     private void FileClose()  
  211.     {  
  212.         if (_writer != null)  
  213.         {  
  214.             _writer.Flush();  
  215.             _writer.Close();  
  216.             _writer.Dispose();  
  217.             _writer = null;  
  218.         }  
  219.     }  
  220.  
  221.     /// <summary>  
  222.     /// Enqueue a new log message and release a semaphore  
  223.     /// </summary>  
  224.     /// <param name="msg">Log message</param>  
  225.     public void Write(LogMessage msg)  
  226.     {  
  227.         if (msg != null)  
  228.         {  
  229.             lock (_lockObjeck)  
  230.             {  
  231.                 _logMessages.Enqueue(msg);  
  232.                 _semaphore.Release();  
  233.             }  
  234.         }  
  235.     }  
  236.  
  237.     /// <summary>  
  238.     /// Write message by message content and type  
  239.     /// </summary>  
  240.     /// <param name="text">log message</param>  
  241.     /// <param name="type">message type</param>  
  242.     public void Write(string text, MessageType type)  
  243.     {  
  244.         Write(new LogMessage(text, type));  
  245.     }  
  246.  
  247.     /// <summary>  
  248.     /// Write Message by datetime and message content and type  
  249.     /// </summary>  
  250.     /// <param name="dateTime">datetime</param>  
  251.     /// <param name="text">message content</param>  
  252.     /// <param name="type">message type</param>  
  253.     public void Write(DateTime dateTime, string text, MessageType type)  
  254.     {  
  255.         Write(new LogMessage(dateTime, text, type));  
  256.     }  
  257.  
  258.     /// <summary>  
  259.     /// Write message ty exception and message type  
  260.     /// </summary>  
  261.     /// <param name="e">exception</param>  
  262.     /// <param name="type">message type</param>  
  263.     public void Write(Exception e, MessageType type)  
  264.     {  
  265.         Write(new LogMessage(e.Message, type));  
  266.     }  
  267.  
  268.     #region IDisposable member  
  269.  
  270.     /// <summary>  
  271.     /// Dispose log  
  272.     /// </summary>  
  273.     public void Dispose()  
  274.     {  
  275.         _state = false;  
  276.     }  
  277.  
  278.     #endregion  
  279. }  
  280.  
  281. /// <summary>  
  282. /// Log Type  
  283. /// </summary>  
  284. /// <remarks>Create log by daily or weekly or monthly or annually</remarks>  
  285. public enum LogType  
  286. {  
  287.     /// <summary>  
  288.     /// Create log by daily  
  289.     /// </summary>  
  290.     Daily,  
  291.  
  292.     /// <summary>  
  293.     /// Create log by weekly  
  294.     /// </summary>  
  295.     Weekly,  
  296.  
  297.     /// <summary>  
  298.     /// Create log by monthly  
  299.     /// </summary>  
  300.     Monthly,  
  301.  
  302.     /// <summary>  
  303.     /// Create log by annually  
  304.     /// </summary>  
  305.     Annually  
  306. }  
  307.  
  308. /// <summary>  
  309. /// Log Message Class  
  310. /// </summary>  
  311. public class LogMessage  
  312. {  
  313.  
  314.     /// <summary>  
  315.     /// Create Log message instance  
  316.     /// </summary>  
  317.     public LogMessage()  
  318.         : this("", MessageType.Unknown)  
  319.     {  
  320.     }  
  321.  
  322.     /// <summary>  
  323.     /// Crete log message by message content and message type  
  324.     /// </summary>  
  325.     /// <param name="text">message content</param>  
  326.     /// <param name="messageType">message type</param>  
  327.     public LogMessage(string text, MessageType messageType)  
  328.         : this(DateTime.Now, text, messageType)  
  329.     {  
  330.     }  
  331.  
  332.     /// <summary>  
  333.     /// Create log message by datetime and message content and message type  
  334.     /// </summary>  
  335.     /// <param name="dateTime">date time </param>  
  336.     /// <param name="text">message content</param>  
  337.     /// <param name="messageType">message type</param>  
  338.     public LogMessage(DateTime dateTime, string text, MessageType messageType)  
  339.     {  
  340.         Datetime = dateTime;  
  341.         Type = messageType;  
  342.         Text = text;  
  343.     }  
  344.  
  345.     /// <summary>  
  346.     /// Gets or sets datetime  
  347.     /// </summary>  
  348.     public DateTime Datetime { getset; }  
  349.  
  350.     /// <summary>  
  351.     /// Gets or sets message content  
  352.     /// </summary>  
  353.     public string Text { getset; }  
  354.  
  355.     /// <summary>  
  356.     /// Gets or sets message type  
  357.     /// </summary>  
  358.     public MessageType Type { getset; }  
  359.  
  360.     /// <summary>  
  361.     /// Get Message to string  
  362.     /// </summary>  
  363.     /// <returns></returns>  
  364.     public new string ToString()  
  365.     {  
  366.         return Datetime.ToString(CultureInfo.InvariantCulture) + "\t" + Text + "\n";  
  367.     }  
  368. }  
  369.  
  370. /// <summary>  
  371. /// Log Message Type enum  
  372. /// </summary>  
  373. public enum MessageType  
  374. {  
  375.     /// <summary>  
  376.     /// unknown type  
  377.     /// </summary>  
  378.     Unknown,  
  379.  
  380.     /// <summary>  
  381.     /// information type  
  382.     /// </summary>  
  383.     Information,  
  384.  
  385.     /// <summary>  
  386.     /// warning type  
  387.     /// </summary>  
  388.     Warning,  
  389.  
  390.     /// <summary>  
  391.     /// error type  
  392.     /// </summary>  
  393.     Error,  
  394.  
  395.     /// <summary>  
  396.     /// success type  
  397.     /// </summary>  
  398.     Success  
  399. }  

Test Case:

  1. public static void TestLog()  
  2. {  
  3.     Log.LogInstance.Write(  "Test Message",MessageType.Information);  
  4.     Log.LogInstance.Write("one",MessageType.Error);  
  5.     Log.LogInstance.Write("two", MessageType.Success);  
  6.     Log.LogInstance.Write("three", MessageType.Warning);  

运行结果:

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#选择正确的集合进行编码
责任编辑:林师授 来源: spring yang的博客
相关推荐

2013-09-10 16:16:19

移动网站性能优化移动web

2011-06-14 09:27:43

高性能WEB开发

2009-09-07 06:18:57

C#窗体设计器

2011-04-18 10:16:30

WEB高性能

2009-02-27 14:46:09

AjaxGWT开发

2009-08-27 16:54:59

C#开发技巧

2009-08-20 10:24:52

C#开发WinForm

2009-08-20 09:30:03

C#开发WinForm

2013-06-17 15:41:09

Windows PhoWP开发JSON生成C#类

2011-04-19 11:06:03

JavaScriptweb

2019-01-02 16:47:46

Golang弹幕

2019-01-02 16:38:37

Golang弹幕

2011-10-18 13:58:32

高性能web

2010-04-15 16:50:58

Oracle动态SQL

2019-01-02 16:50:30

Golang弹幕

2024-08-13 14:14:55

场景数据库API

2011-04-07 13:53:25

Web工具

2009-08-24 09:55:24

C#集成开发环境

2009-08-24 10:10:09

C#复合控件

2009-09-11 12:07:12

C# WinForm控
点赞
收藏

51CTO技术栈公众号