概述
项目中要在操作数据库的异常处理中加入写Log日志,对于商业上有要求,写log时对其它操作尽可能影响小,不能因为加入log导致耗时太多。
设计思想
在写入日志时利用Queue来管理,写日志有一个专门的backgroud线程来处理,如果没有日志要写,这个线程处于wait状态,这就有了线程的异步处理。
简单的实现方式
-
-
-
-
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 线程。
代码设计
-
-
-
-
-
-
-
public class Log : IDisposable
- {
-
-
private static Queue<LogMessage> _logMessages;
-
-
-
private static string _logDirectory;
-
-
-
private static bool _state;
-
-
-
private static LogType _logType;
-
-
-
private static DateTime _timeSign;
-
-
-
private static StreamWriter _writer;
-
-
-
-
-
private Semaphore _semaphore;
-
-
-
-
-
private static Log _log;
-
-
-
-
-
public static Log LogInstance
- {
-
get { return _log ?? (_log = new Log()); }
- }
-
-
private object _lockObjeck;
-
-
-
-
-
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();
- }
- }
-
-
-
-
-
private Log()
- {
- Initialize();
- }
-
-
-
-
-
public LogType LogType
- {
-
get { return _logType; }
-
set { _logType = value; }
- }
-
-
-
-
-
private void Work()
- {
-
while (true)
- {
-
-
if (_logMessages.Count > 0)
- {
- FileWriteMessage();
- }
-
else
-
if (WaitLogMessage()) break;
- }
- }
-
-
-
-
-
private void FileWriteMessage()
- {
-
LogMessage logMessage=null;
-
lock (_lockObjeck)
- {
-
if(_logMessages.Count>0)
- logMessage = _logMessages.Dequeue();
- }
-
if (logMessage != null)
- {
- FileWrite(logMessage);
- }
- }
-
-
-
-
-
-
private bool WaitLogMessage()
- {
-
-
if (_state)
- {
-
WaitHandle.WaitAny(new WaitHandle[] { _semaphore }, -1, false);
-
return false;
- }
- FileClose();
-
return true;
- }
-
-
-
-
-
-
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);
- }
-
-
-
-
-
-
private void FileWrite(LogMessage msg)
- {
-
try
- {
-
if (_writer == null)
- {
- FileOpen();
- }
-
else
- {
-
-
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);
- }
- }
-
-
-
-
-
private void FileOpen()
- {
-
_writer = new StreamWriter(Path.Combine(_logDirectory, GetFilename()), true, Encoding.UTF8);
- }
-
-
-
-
-
private void FileClose()
- {
-
if (_writer != null)
- {
- _writer.Flush();
- _writer.Close();
- _writer.Dispose();
-
_writer = null;
- }
- }
-
-
-
-
-
-
public void Write(LogMessage msg)
- {
-
if (msg != null)
- {
-
lock (_lockObjeck)
- {
- _logMessages.Enqueue(msg);
- _semaphore.Release();
- }
- }
- }
-
-
-
-
-
-
-
public void Write(string text, MessageType type)
- {
-
Write(new LogMessage(text, type));
- }
-
-
-
-
-
-
-
-
public void Write(DateTime dateTime, string text, MessageType type)
- {
-
Write(new LogMessage(dateTime, text, type));
- }
-
-
-
-
-
-
-
public void Write(Exception e, MessageType type)
- {
-
Write(new LogMessage(e.Message, type));
- }
-
-
#region IDisposable member
-
-
-
-
-
public void Dispose()
- {
-
_state = false;
- }
-
-
#endregion
- }
-
-
-
-
-
-
public enum LogType
- {
-
-
-
- Daily,
-
-
-
-
- Weekly,
-
-
-
-
- Monthly,
-
-
-
-
- Annually
- }
-
-
-
-
-
public class LogMessage
- {
-
-
-
-
-
public LogMessage()
-
: this("", MessageType.Unknown)
- {
- }
-
-
-
-
-
-
-
public LogMessage(string text, MessageType messageType)
-
: this(DateTime.Now, text, messageType)
- {
- }
-
-
-
-
-
-
-
-
public LogMessage(DateTime dateTime, string text, MessageType messageType)
- {
- Datetime = dateTime;
- Type = messageType;
- Text = text;
- }
-
-
-
-
-
public DateTime Datetime { get; set; }
-
-
-
-
-
public string Text { get; set; }
-
-
-
-
-
public MessageType Type { get; set; }
-
-
-
-
-
-
public new string ToString()
- {
-
return Datetime.ToString(CultureInfo.InvariantCulture) + "\t" + Text + "\n";
- }
- }
-
-
-
-
-
public enum MessageType
- {
-
-
-
- Unknown,
-
-
-
-
- Information,
-
-
-
-
- Warning,
-
-
-
-
- Error,
-
-
-
-
- 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的建议,改了部分代码。
请发表评论