十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
概述

项目中要在操作数据库的异常处理中加入写Log日志,对于商业上有要求,写log时对其它操作尽可能影响小,不能因为加入log导致耗时太多。
设计思想
在写入日志时利用Queue来管理,写日志有一个专门的backgroud线程来处理,如果没有日志要写,这个线程处于wait状态,这就有了线程的异步处理。
简单的实现方式
- //
 - //Write Log
 - //
 - 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;
 - }
 - }
 
我们的设计图
而后我们在AddLogMessage时semaphore.Release()就能唤醒wait中的log 线程。
代码设计
- ///
 - /// Author: spring yang
 - /// Create time:2012/3/30
 - /// Log Help class
 - ///
 - ///
 High performance log class - public class Log : IDisposable
 - {
 - //Log Message queue
 - private static Queue
 _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;
 - ///
 - /// Wait enqueue wirte log message semaphore will release
 - ///
 - private Semaphore _semaphore;
 - ///
 - /// Single instance
 - ///
 - private static Log _log;
 - ///
 - /// Gets a single instance
 - ///
 - public static Log LogInstance
 - {
 - get { return _log ?? (_log = new Log()); }
 - }
 - private object _lockObjeck;
 - ///
 - /// Initialize Log instance
 - ///
 - 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
 (); - var thread = new Thread(Work) {IsBackground = true};
 - thread.Start();
 - }
 - }
 - ///
 - /// Create a log instance
 - ///
 - private Log()
 - {
 - Initialize();
 - }
 - ///
 - /// Log save name type,default is daily
 - ///
 - public LogType LogType
 - {
 - get { return _logType; }
 - set { _logType = value; }
 - }
 - ///
 - /// Write Log file work method
 - ///
 - private void Work()
 - {
 - while (true)
 - {
 - //Determine log queue have record need wirte
 - if (_logMessages.Count > 0)
 - {
 - FileWriteMessage();
 - }
 - else
 - if (WaitLogMessage()) break;
 - }
 - }
 - ///
 - /// Write message to log file
 - ///
 - private void FileWriteMessage()
 - {
 - LogMessage logMessage=null;
 - lock (_lockObjeck)
 - {
 - if(_logMessages.Count>0)
 - logMessage = _logMessages.Dequeue();
 - }
 - if (logMessage != null)
 - {
 - FileWrite(logMessage);
 - }
 - }
 - ///
 - /// The thread wait a log message
 - ///
 - ///
 is close or not - 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;
 - }
 - ///
 - /// Gets file name by log type
 - ///
 - ///
 log file name - 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);
 - }
 - ///
 - /// Write log file message
 - ///
 - ///
 - 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);
 - }
 - }
 - ///
 - /// Open log file write log message
 - ///
 - private void FileOpen()
 - {
 - _writer = new StreamWriter(Path.Combine(_logDirectory, GetFilename()), true, Encoding.UTF8);
 - }
 - ///
 - /// Close log file
 - ///
 - private void FileClose()
 - {
 - if (_writer != null)
 - {
 - _writer.Flush();
 - _writer.Close();
 - _writer.Dispose();
 - _writer = null;
 - }
 - }
 - ///
 - /// Enqueue a new log message and release a semaphore
 - ///
 - /// Log message
 - public void Write(LogMessage msg)
 - {
 - if (msg != null)
 - {
 - lock (_lockObjeck)
 - {
 - _logMessages.Enqueue(msg);
 - _semaphore.Release();
 - }
 - }
 - }
 - ///
 - /// Write message by message content and type
 - ///
 - /// log message
 - /// message type
 - public void Write(string text, MessageType type)
 - {
 - Write(new LogMessage(text, type));
 - }
 - ///
 - /// Write Message by datetime and message content and type
 - ///
 - /// datetime
 - /// message content
 - /// message type
 - public void Write(DateTime dateTime, string text, MessageType type)
 - {
 - Write(new LogMessage(dateTime, text, type));
 - }
 - ///
 - /// Write message ty exception and message type
 - ///
 - /// exception
 - /// message type
 - public void Write(Exception e, MessageType type)
 - {
 - Write(new LogMessage(e.Message, type));
 - }
 - #region IDisposable member
 - ///
 - /// Dispose log
 - ///
 - public void Dispose()
 - {
 - _state = false;
 - }
 - #endregion
 - }
 - ///
 - /// Log Type
 - ///
 - ///
 Create log by daily or weekly or monthly or annually - public enum LogType
 - {
 - ///
 - /// Create log by daily
 - ///
 - Daily,
 - ///
 - /// Create log by weekly
 - ///
 - Weekly,
 - ///
 - /// Create log by monthly
 - ///
 - Monthly,
 - ///
 - /// Create log by annually
 - ///
 - Annually
 - }
 - ///
 - /// Log Message Class
 - ///
 - public class LogMessage
 - {
 - ///
 - /// Create Log message instance
 - ///
 - public LogMessage()
 - : this("", MessageType.Unknown)
 - {
 - }
 - ///
 - /// Crete log message by message content and message type
 - ///
 - /// message content
 - /// message type
 - public LogMessage(string text, MessageType messageType)
 - : this(DateTime.Now, text, messageType)
 - {
 - }
 - ///
 - /// Create log message by datetime and message content and message type
 - ///
 - /// date time
 - /// message content
 - /// message type
 - public LogMessage(DateTime dateTime, string text, MessageType messageType)
 - {
 - Datetime = dateTime;
 - Type = messageType;
 - Text = text;
 - }
 - ///
 - /// Gets or sets datetime
 - ///
 - public DateTime Datetime { get; set; }
 - ///
 - /// Gets or sets message content
 - ///
 - public string Text { get; set; }
 - ///
 - /// Gets or sets message type
 - ///
 - public MessageType Type { get; set; }
 - ///
 - /// Get Message to string
 - ///
 - ///
 - public new string ToString()
 - {
 - return Datetime.ToString(CultureInfo.InvariantCulture) + "\t" + Text + "\n";
 - }
 - }
 - ///
 - /// Log Message Type enum
 - ///
 - public enum MessageType
 - {
 - ///
 - /// unknown type
 - ///
 - Unknown,
 - ///
 - /// information type
 - ///
 - Information,
 - ///
 - /// warning type
 - ///
 - Warning,
 - ///
 - /// error type
 - ///
 - Error,
 - ///
 - /// success type
 - ///
 - Success
 - }
 
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);
 - }
 
运行结果:
接受Mainz的建议,改了部分代码。
Mainz:http://www.cnblogs.com/Mainz/