我想编写一个记录器类,它根据用户操作将输出写入日志文件。我为此编写了一个logmessage类。以下是我所拥有的。
public class LogMessage
{
private static Object padlock = new Object();
private static string serviceDirectory ="C:\\MySite\\";
private static string filePath = "\\Logs\\Combined\\ActivityMonitorLog-" + DateTime.Now.ToString("dd'-'MM'-'yyyy") + ".log";
private static volatile LogMessage instance = new LogMessage();
public static LogMessage Instance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
instance = new LogMessage();
}
}
return instance;
}
}
public void SaveLogMessage(string userName, string message, string stackTrace)
{
lock (padlock)
{
using (StreamWriter logWriter =
new StreamWriter(serviceDirectory + filePath, true))
{
string logMessage = "";
if (!string.IsNullOrEmpty(stackTrace))
logMessage = string.Format("{0} >> user : {1} ::: {2} ::: stack trace ::: {3}", DateTime.Now.ToString(), userName, message,stackTrace);
else
logMessage = string.Format("{0} >> user : {1} ::: {2}", DateTime.Now.ToString(), userName, message);
logWriter.WriteLine(logMessage);
}
}
}
}
当我想要做一个日志条目时,我正在调用下面的方法
LogMessage.Instance.SaveLogMessage("My User", "Enter Logout PageLoad : Current Method :" + "Page_Load @ Logout.aspx.cs", "");
我相信我已经实现了单件部件和线程安全性。但我不认为这是非阻塞的,因为多个用户同时登录,每个用户都必须等到文件可用才能被写入。我在考虑使用backgroundworker
从LogMessage单例对象调用此SaveLogMessage()。这是正确的做法吗?
更新
我使用backgroundworker实现了这个,完整的类和答案中提到了如何调用。感谢@bret和@huan的投入
答案 0 :(得分:1)
对于你的"实例"领域,使用" readonly"而不是" volatile"因为该字段的值永远不会改变。
您甚至不需要公共实例属性 - 您可以将SaveLogMessage转换为静态方法并直接使用它。
在SaveLogMessage主体中,您可以使用Task.Run(()=> {...})在后台线程上执行日志记录操作以使其无阻塞。如果您经常进行日志记录,这可能效率不高。
请考虑使用System.Diagnostics.Trace,这样可以提供更大的灵活性。
答案 1 :(得分:1)
btw为什么不使用log4net或任何其他现有的库。
答案 2 :(得分:1)
最后,我设法使用后台工作程序实现了非阻塞,线程安全的单例日志记录类。我正在提交我的解决方案,以防有人发现它有用。
using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Diagnostics;
using System.Web.Configuration;
/// <summary>
/// Summary description for LogMessage
/// </summary>
public class LogMessage
{
static ReaderWriterLock locker = new ReaderWriterLock();
private static string serviceDirectory = HttpContext.Current != null ?
AppDomain.CurrentDomain.BaseDirectory :
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
private static string fullpath = serviceDirectory + "\\ActivityLog.log";
private static readonly LogMessage instance = new LogMessage();
public static LogMessage Instance
{
get { return instance; }
}
public void SaveLogMessage(string userName, string message, string stackTrace, bool inOut)
{
bool EnableActivityLogging = false;
if (string.IsNullOrEmpty(WebConfigurationManager.AppSettings["EnableActivityLogging"]))
return;
EnableActivityLogging = Convert.ToBoolean(WebConfigurationManager.AppSettings["EnableActivityLogging"]);
if (!EnableActivityLogging)
return;
BackgroundWorker logbw = new BackgroundWorker();
logbw.DoWork += logbw_DoWork;
logbw.RunWorkerCompleted += logbw_RunWorkerCompleted;
List<string> paramList = new List<string>();
paramList.Add(userName);
paramList.Add(message);
paramList.Add(stackTrace);
paramList.Add(inOut.ToString());
if (!logbw.IsBusy)
{
logbw.RunWorkerAsync(paramList);
}
}
void logbw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.Write("Log Message Background Worker is now free...");
}
void logbw_DoWork(object sender, DoWorkEventArgs e)
{
List<string> paramList = (List<string>)e.Argument;
string userName = paramList[0].ToString();
string message = paramList[1].ToString();
string stackTrace = paramList[2].ToString();
bool inOut = bool.Parse(paramList[3].ToString());
try
{
locker.AcquireWriterLock(int.MaxValue);
using (StreamWriter logWriter =
new StreamWriter(fullpath, true))
{
string logMessage = "";
if (!string.IsNullOrEmpty(stackTrace))
{
if (inOut)//IN
{
logMessage = string.Format("{0} U:{1} IN:{2} E:{3}", DateTime.Now.ToString(), userName, message, stackTrace);
}
else//OUT
{
logMessage = string.Format("{0} U:{1} OUT:{2} E:{3}", DateTime.Now.ToString(), userName, message, stackTrace);
}
}
else
{
if (inOut)//IN
{
logMessage = string.Format("{0} U:{1} IN:{2}", DateTime.Now.ToString(), userName, message);
}
else//OUT
{
logMessage = string.Format("{0} U:{1} OUT:{2}", DateTime.Now.ToString(), userName, message);
}
}
logWriter.WriteLine(logMessage);
}
}
finally
{
locker.ReleaseWriterLock();
}
}
}
现在我可以像下面这样使用这个单例对象来保存日志条目
LogMessage.Instance.SaveLogMessage(Context.User.Identity.Name, "Custom Message" + " M:" + MethodInfo.GetCurrentMethod().Name + "@" + Path.GetFileName(Page.AppRelativeVirtualPath), "", true);