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; } }
我们的设计图
而后我们在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 }
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/
欢迎各位参与讨论,如果觉得对你有帮助,请点击 推荐下,万分谢谢.
作者:spring yang
出处:http://www.cnblogs.com/springyangwc/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。