次は、かなり簡単なスレッドセーフロギングクラスを実装する正しい方法でしょうか?
TextWriter
を明示的に閉じることはありませんが、それは問題ですか?
最初に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();
}
}
ここでは他の回答とはまったく異なるアプローチを取り、より優れたスレッド対応コードの書き方を実際に学びたいと想定し、私たちからのサードパーティの提案を探していないと仮定します1。)
他の人が言ったように、スレッドセーフTextWriter
を作成しています。つまり、WriteLineの呼び出しはスレッドセーフです。つまり、WriteLine
の呼び出しが次のように実行されることを意味しません。アトミック操作。つまり、4つのWriteLine呼び出しが順番に発生するという保証はありません。スレッドセーフTextWriter
を持っているかもしれませんが、スレッドセーフLogger.Log
メソッドを持っていません;)なぜですか?これらの4つの呼び出しのどの時点でも、別のスレッドがLog
を呼び出すことを決定する可能性があるためです。これは、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();
}
}
これで、スレッドセーフTextWriter
とスレッドセーフLogger
ができました。
理にかなっていますか?
TextWriter.Synchronized を呼び出すと、TextWriter
の単一インスタンスが保護されますが、書き込みが同期されないため、1つの "Log"呼び出しがファイル内にまとめられます。
複数のスレッドからWrite
(または内部Log
インスタンスを使用してTextWriter
)を呼び出すと、個々のWriteLine
呼び出しが織り込まれ、日付と時刻が作成される場合があります使用できないスタンプ。
私は、このためにすでに存在するサードパーティのログソリューションを個人的に使用します。それがオプションではない場合、フレームワークのTextWriter.Synchronized
ラッパー。
このクラス(.NET 2.0の一部)を調べる必要があります。独自のロガーを「作成」する必要はありません。テキストファイル、イベントビューなどにログを記録できます。
http://msdn.Microsoft.com/en-us/library/system.diagnostics.tracesource.aspx
「Log」メソッドは次のようになります(「traceSource」と呼ばれる内部メンバー変数があると仮定します)。
public void Log(TraceEventType eventType, string message)
{
this.traceSource.TraceEvent(eventType, 0, message);
this.traceSource.Flush();
}
これをサポートするのは、TraceSourceに名前を付け、いくつかの構成設定を持つ構成セクションです。ロガーでTraceSourceを構築する場合、設定で指定されたトレースソースの1つでインスタンス化することを想定しています。
<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>
また、ロガーを静的にしないでください。代わりに、依存性注入/ IOCにはEnterprise Library 5.0 Unityを使用してください。
お役に立てれば!
今日、ロギングの問題について議論しているときに、誰かがこの投稿を指摘してくれました。ここにはすでにかなり良い答えがありますが、完全にLogger
の方法でまったく同じことを行うThreadsafe
クラスの単純なバージョンを示すために、答えを追加しています。
ここで注目すべき主な点は、TextWriter.Synchronized
は、適切なlock
内にファイルを書き込むため、スレッドセーフのために必要です。
注:これは、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(),
DateTime.Now.ToLongTimeString(), logMessage));
}
}
}
何かを記録するには、単に
Logger.Log("Some important event has occurred!");
そして、このようなログエントリを作成します
ログオン:2015年10月7日:02:11:23
メッセージ:いくつかの重要なイベントが発生しました!
--------------------
コードをインスツルメントする簡単な方法を探している場合、この機能は.NET内にすでに存在します。
http://msdn.Microsoft.com/en-us/library/system.diagnostics.trace.aspx
さらに、サードパーティのツールを使用すると、ログの堅牢なソリューションが得られます。例には、 log4net 、 nLog 、および Enterprise Library が含まれます。
私はこれで車輪を再発明しないことを本当にお勧めします:)