web-dev-qa-db-ja.com

log4netの非同期ラッパーを作成するにはどうすればよいですか?

デフォルトでは、log4netは同期ロギングメカニズムであり、log4netで非同期ロギングを行う方法があるかどうか疑問に思っていましたか?

30

Log4netのWebサイトにアクセスすると、いくつかの例が見つかりますが、そのうちの1つは非同期アペンダーです。

http://logging.Apache.org/log4net/release/example-apps.html

これらの例はまだ使用していないため、どちらの方法でも保証することはできません。

以下は、コードリポジトリのlog4net Examples領域からの実際の非同期アペンダーへのリンクです。

http://svn.Apache.org/viewvc/logging/log4net/trunk/examples/net/2.0/Appenders/SampleAppendersApp/cs/src/Appender/AsyncAppender.cs?view=markup

私はそれを簡単に調べたところ、明らかに1つ以上の「従来の」アペンダーのラッパーとして機能しています。各ロギング要求(1つ以上のLoggingEventオブジェクトを含む)で、ThreadPoolスレッドを使用してLoggingEventsをラップされたAppenderのリストに転送します。

13
wageoghe

参照用の完全なソリューションを提供したかっただけです。いくつかの重要な項目であるFixFlagsを使用すると、実際にロギングを実行しているスレッドをキャプチャできます。ブロッキングコレクションはReactiveExtensionsにあります。ここでの要点は、転送アペンダーが非同期のものを処理してから、LoggingEventを標準のLog4Netアペンダーに転送するだけです。ホイールを再発明する必要はありません。

/// <summary>
/// Provides an extension for the log4net libraries to provide ansynchronous logging capabilities to the log4net architecture
/// </summary>
public class AsyncLogFileAppender : log4net.Appender.ForwardingAppender
{
    private static int _asyncLogFileAppenderCount = 0;
    private readonly Thread _loggingThread;
    private readonly BlockingCollection<log4net.Core.LoggingEvent> _logEvents = new BlockingCollection<log4net.Core.LoggingEvent>();

    protected override void Append(log4net.Core.LoggingEvent loggingEvent)
    {
        loggingEvent.Fix = FixFlags.ThreadName;
        _logEvents.Add(loggingEvent);
    }

    public AsyncLogFileAppender()
    {

        _loggingThread = new Thread(LogThreadMethod) { IsBackground = true, Name = "AsyncLogFileAppender-" + Interlocked.Increment(ref _asyncLogFileAppenderCount), };
        _loggingThread.Start();
    }

    private void LogThreadMethod()
    {
        while (true)
        {
            LoggingEvent le = _logEvents.Take();
            foreach (var appender in Appenders)
            {
                appender.DoAppend(le);
            }
        }
    }
}

次に、log4net.xmlでアペンダーを設定します

<!-- Standard form output target location and form -->
<appender name="StandardAppender" type="TSUIC.Logging.AsyncLogFileAppender">
<appender-ref ref="StandardAppenderSync" />
</appender>

<appender name="StandardAppenderSync" type="log4net.Appender.RollingFileAppender">
    <!-- The standard pattern layout to use -->
    <file value="log\Log_" />
    <appendToFile value="true" />
    <rollingStyle value="Date" />
    <maxSizeRollBackups value="-1" />
    <maximumFileSize value="5GB" />
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    <staticLogFileName value="false" />
    <datePattern value="yyyyMMdd'.txt'" />
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
    </layout>
</appender>

更新:

log4net.ThreadContext.Properties["CustomColumn"]」のようなlog4netのコンテキストを使用する場合

次に、上記のコードを次のように更新する必要があります

loggingEvent.Fix = FixFlags.All;
13

これが私のやり方です:

Task.Factory.StartNew(() => log.Info("My Info"));

そのようにして、log4netは非同期に別のスレッドでロギングを実行します...

ところで、TaskクラスはSystem.Threading.Tasks名前空間。

11
Dean Kuga

ここにあるアイデアの一部は正しくなく、無効/古いデータ、順不同のロギング、または非常に悪いパフォーマンスをもたらします。たとえば、受け入れられた回答は、log4net AsyncAppenderを使用することを提案しています。これは、ThreadPoolを使用して、一部の問題ではないかもしれない順不同のエントリを生成しますが、ログイベントを次々に表示したいまた、パフォーマンスが著しく低下し、ThreadPoolに過度の負担がかかる可能性があります。また、ログエントリがバッチ処理されません。ジョナサンによって提案された答えは確かにはるかに良い解決策ですが、それでも最適なパフォーマンスが欠けています。

これがどのように実装されるべきかの良い例が見つかります [〜#〜]ここ[〜#〜] とベンチマーク結果と説明 [〜#〜]ここ[〜# 〜]

このソリューションのもう1つの優れた機能は、ForwarderではなくAppenderとして実装されており、ユーザーが複数のAppenderを含めて、同時。

7
MaYaN

今週私はこの問題に遭遇しましたが、スレッドのアプリケーションの残りの部分を使い果たしてしまう可能性があるので、スレッドプールへのリクエストをオフにしたくはありませんでした。バッファを介して供給されます。ここで確認してください: https://github.com/cjbhaines/Log4Net.Async

5
Chris Haines

https://github.com/cjbhaines/Log4Net.Async

現在、非同期のlog4netメソッドを利用できます。最新の答えを探している人のために。

https://www.nuget.org/packages/Log4Net.Async/