独自のロギングフレームワークを実装しています。以下は、ログエントリを受け取り、メソッドBaseLogger
を実装する実際のロガーにプッシュするmyです。abstract Log
非同期方式でのロギングにはC#TPLを使用します。TPLの代わりにスレッドを使用しています。(TPLタスクは実際のスレッドを保持しません。したがって、アプリケーションのすべてのスレッドが終了すると、タスクも停止し、すべての「待機中」のログエントリが失われます。)
public abstract class BaseLogger
{
// ... Omitted properties constructor .etc. ... //
public virtual void AddLogEntry(LogEntry entry)
{
if (!AsyncSupported)
{
// the underlying logger doesn't support Async.
// Simply call the log method and return.
Log(entry);
return;
}
// Logger supports Async.
LogAsync(entry);
}
private void LogAsync(LogEntry entry)
{
lock (LogQueueSyncRoot) // Make sure we ave a lock before accessing the queue.
{
LogQueue.Enqueue(entry);
}
if (LogThread == null || LogThread.ThreadState == ThreadState.Stopped)
{ // either the thread is completed, or this is the first time we're logging to this logger.
LogTask = new new Thread(new ThreadStart(() =>
{
while (true)
{
LogEntry logEntry;
lock (LogQueueSyncRoot)
{
if (LogQueue.Count > 0)
{
logEntry = LogQueue.Dequeue();
}
else
{
break;
// is it possible for a message to be added,
// right after the break and I leanve the lock {} but
// before I exit the loop and task gets 'completed' ??
}
}
Log(logEntry);
}
}));
LogThread.Start();
}
}
// Actual logger implimentations will impliment this method.
protected abstract void Log(LogEntry entry);
}
AddLogEntry
複数のスレッドから同時に呼び出すことができることに注意してください。
私の質問は、この実装がログエントリを失う可能性はありますか?私のスレッドがbreakステートメントを含むループを存在し、ロックブロックを終了した直後に、キューにログエントリを追加することは可能ですか?これはelse句にあり、スレッドはまだ「実行中」の状態。
キューを使用しているため、エントリを見逃した場合でも、次にログに記録するリクエストによって、失われたエントリもプッシュされることを認識しています。ただし、これは、特にアプリケーションの最後のログエントリで発生する場合は、受け入れられません。
また、同じものを実装できるかどうか、どのように実装できるかを教えてください。ただし、新しいC#5.0async
とawait
キーワードをよりクリーンなコードで使用します。.NET4.5が必要でもかまいません。
前もって感謝します。