以下是使用BlockingCollection以Producer/Consumer模式(使用.Net 4)實現的日誌示例。該接口是:
namespace Log
{
public interface ILogger
{
void WriteLine(string msg);
void WriteError(string errorMsg);
void WriteError(string errorObject, string errorAction, string errorMsg);
void WriteWarning(string errorObject, string errorAction, string errorMsg);
}
}
和完整的類代碼是在這裏:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Log
{
// Reentrant Logger written with Producer/Consumer pattern.
// It creates a thread that receives write commands through a Queue (a BlockingCollection).
// The user of this log has just to call Logger.WriteLine() and the log is transparently written asynchronously.
public class Logger : ILogger
{
BlockingCollection<Param> bc = new BlockingCollection<Param>();
// Constructor create the thread that wait for work on .GetConsumingEnumerable()
public Logger()
{
Task.Factory.StartNew(() =>
{
foreach (Param p in bc.GetConsumingEnumerable())
{
switch (p.Ltype)
{
case Log.Param.LogType.Info:
const string LINE_MSG = "[{0}] {1}";
Console.WriteLine(String.Format(LINE_MSG, LogTimeStamp(), p.Msg));
break;
case Log.Param.LogType.Warning:
const string WARNING_MSG = "[{3}] * Warning {0} (Action {1} on {2})";
Console.WriteLine(String.Format(WARNING_MSG, p.Msg, p.Action, p.Obj, LogTimeStamp()));
break;
case Log.Param.LogType.Error:
const string ERROR_MSG = "[{3}] *** Error {0} (Action {1} on {2})";
Console.WriteLine(String.Format(ERROR_MSG, p.Msg, p.Action, p.Obj, LogTimeStamp()));
break;
case Log.Param.LogType.SimpleError:
const string ERROR_MSG_SIMPLE = "[{0}] *** Error {1}";
Console.WriteLine(String.Format(ERROR_MSG_SIMPLE, LogTimeStamp(), p.Msg));
break;
default:
Console.WriteLine(String.Format(LINE_MSG, LogTimeStamp(), p.Msg));
break;
}
}
});
}
~Logger()
{
// Free the writing thread
bc.CompleteAdding();
}
// Just call this method to log something (it will return quickly because it just queue the work with bc.Add(p))
public void WriteLine(string msg)
{
Param p = new Param(Log.Param.LogType.Info, msg);
bc.Add(p);
}
public void WriteError(string errorMsg)
{
Param p = new Param(Log.Param.LogType.SimpleError, errorMsg);
bc.Add(p);
}
public void WriteError(string errorObject, string errorAction, string errorMsg)
{
Param p = new Param(Log.Param.LogType.Error, errorMsg, errorAction, errorObject);
bc.Add(p);
}
public void WriteWarning(string errorObject, string errorAction, string errorMsg)
{
Param p = new Param(Log.Param.LogType.Warning, errorMsg, errorAction, errorObject);
bc.Add(p);
}
string LogTimeStamp()
{
DateTime now = DateTime.Now;
return now.ToShortTimeString();
}
}
}
在此示例中,用於將信息傳遞給通過BlockingCollection寫入線程內部帕拉姆類是:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Log
{
internal class Param
{
internal enum LogType { Info, Warning, Error, SimpleError };
internal LogType Ltype { get; set; } // Type of log
internal string Msg { get; set; } // Message
internal string Action { get; set; } // Action when error or warning occurs (optional)
internal string Obj { get; set; } // Object that was processed whend error or warning occurs (optional)
internal Param()
{
Ltype = LogType.Info;
Msg = "";
}
internal Param(LogType logType, string logMsg)
{
Ltype = logType;
Msg = logMsg;
}
internal Param(LogType logType, string logMsg, string logAction, string logObj)
{
Ltype = logType;
Msg = logMsg;
Action = logAction;
Obj = logObj;
}
}
}
與其編寫自己的日誌記錄實現,確保你已經看過[log4net](http://logging.apache.org/log4net/index.html)等。如果這是一個僅限Windows的應用程序,並行性能是一個問題,請考慮[NTrace](http://ntrace.codeplex.com/)。 – hemp 2010-06-03 05:44:51