如何解决线程安全日志记录类的实现
| 以下是实现相当简单的线程安全日志记录类的正确方法吗? 我知道我从来没有明确地关闭ѭ0,这会是一个问题吗? 最初使用TextWriter.Synchronized
方法时,它似乎无法工作,直到我在静态构造函数中对其进行了初始化并将其设置为只读,如下所示:
public static class Logger
{
static readonly TextWriter tw;
static Logger()
{
tw = TextWriter.Synchronized(File.AppendText(SPath() + \"\\\\Log.txt\"));
}
public static string SPath()
{
return ConfigManager.GetAppSetting(\"logPath\");
}
public static void Write(string logMessage)
{
try
{
Log(logMessage,tw);
}
catch (IOException e)
{
tw.Close();
}
}
public static void Log(string logMessage,TextWriter w)
{
w.WriteLine(\"{0} {1}\",DateTime.Now.ToLongTimeString(),DateTime.Now.ToLongDateString());
w.WriteLine(\" :\");
w.WriteLine(\" :{0}\",logMessage);
w.WriteLine(\"-------------------------------\");
// Update the underlying file.
w.Flush();
}
}
解决方法
在这里,我将采用与其他答案完全不同的方法,并假设您实际上是想学习如何编写更好的线程感知代码,并且没有从我们这里寻求第三者的建议(即使您可能最终会得到建议)使用一个。)
正如其他人所说,您正在创建一个线程安全的“ 0”,这意味着对WriteLine的调用是线程安全的,这并不意味着一堆对
WriteLine
的调用将作为原子操作执行。我的意思是,不能保证四个WriteLine调用将按顺序进行。您可能具有线程安全的TextWriter
,但是没有线程安全的Logger.Log
方法;)为什么?因为在这四个调用期间的任何时候,另一个线程可能会决定也调用ѭ7。这意味着您的WriteLine
通话将不同步。解决此问题的方法是使用lock
语句,如下所示:
private static readonly object _syncObject = new object();
public static void Log(string logMessage,TextWriter w) {
// only one thread can own this lock,so other threads
// entering this method will wait here until lock is
// available.
lock(_syncObject) {
w.WriteLine(\"{0} {1}\",DateTime.Now.ToLongTimeString(),DateTime.Now.ToLongDateString());
w.WriteLine(\" :\");
w.WriteLine(\" :{0}\",logMessage);
w.WriteLine(\"-------------------------------\");
// Update the underlying file.
w.Flush();
}
}
因此,现在您有了一个线程安全的“ 0”和一个线程安全的“ 12”。
合理?
, 在调用TextWriter.Synchronized时将保护that0ѭ的单个实例,但不会同步您的写入,因此一个\“ Log \”调用将保留在文件内。
如果从多个线程调用Write
(或使用内部TextWriter
实例使用Log
),则各个inter4ѭ调用可能会交织在一起,从而使日期和时间戳无法使用。
我个人将使用为此已存在的第三方日志记录解决方案。如果不是这种选择,那么自己同步(即使使用简单的锁)也可能比使用框架的ѭ1包装器更为有用。
, 有人在今天讨论一些日志记录问题时将我指向这篇文章。我们已经在这里有了很好的答案,但是我添加我的答案只是为了展示Logger
类的一个简单版本,该类以完全Threadsafe
的方式做同样的事情。
这里要注意的一件事是,为了安全起见,不需要ѭ1,因为我们正在适当的ѭ9内写入文件。
注意:这已经在x0n答案的注释部分中进行了讨论。
public static class Logger
{
static readonly object _locker = new object();
public static void Log(string logMessage)
{
try
{
var logFilePath = Path.Combine(@\"C:\\YourLogDirectoryHere\",\"Log.txt\");
//Use this for daily log files : \"Log\" + DateTime.Now.ToString(\"yyyy-MM-dd\") + \".txt\";
WriteToLog(logMessage,logFilePath);
}
catch (Exception e)
{
//log log-exception somewhere else if required!
}
}
static void WriteToLog(string logMessage,string logFilePath)
{
lock (_locker)
{
File.AppendAllText(logFilePath,string.Format(\"Logged on: {1} at: {2}{0}Message: {3}{0}--------------------{0}\",Environment.NewLine,DateTime.Now.ToLongDateString(),logMessage));
}
}
}
要记录一些东西,只需调用
Logger.Log(\"Some important event has occurred!\");
它会像这样创建一个日志条目
登录:2015年10月7日在:02:11:23
消息:发生了一些重要事件!
--------------------
, 您应该研究此类(.NET 2.0的一部分),而无需“创建”自己的记录器。使您可以登录到文本文件,事件视图等。
http://msdn.microsoft.com/zh-CN/library/system.diagnostics.tracesource.aspx
您的\“ Log \”方法可能类似于以下内容(假设有一个名为\'traceSource \'的内部成员变量):
public void Log(TraceEventType eventType,string message)
{
this.traceSource.TraceEvent(eventType,message);
this.traceSource.Flush();
}
支持此操作的是一个配置部分,该部分命名TraceSource并具有一些Config设置。假定在记录器中构造TraceSource时,将使用配置中命名的跟踪源之一实例化它。
<system.diagnostics>
<sources>
<source name=\"Sample\" switchValue=\"Information,ActivityTracing\">
<listeners>
<add name=\"file\"
initializeData=\"C:\\temp\\Sample-trace.log\"
traceOutputOptions=\"DateTime\"
type=\"System.Diagnostics.TextWriterTraceListener,System,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089\"/>
</listeners>
</source>
</sources>
另外,请不要将记录器设为静态。相反,请使用Enterprise Library 5.0 Unity进行依赖性注入/ IOC。
希望这可以帮助!
, 如果您正在寻找一种检测代码的简单方法,则该工具已经在.NET中存在:
http://msdn.microsoft.com/zh-CN/library/system.diagnostics.trace.aspx
此外,第三方工具将为您提供强大的日志记录解决方案;示例包括log4net,nLog和企业库。
我真的建议不要在此方面重新发明轮子:)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。