2

Trace大規模なアプリケーションをクラスの使用から を介して通知を出力するように移行しようとしていlog4netます。TraceListenerそのため、出力を log4net のメッセージングにリダイレクトするカスタムを作成しました (この投稿に触発されました)。

public class Log4netTraceListener : TraceListener
{
    private static readonly ILog logger = LogManager.GetLogger("Log4netTraceListener"); // Line 19

    public Log4netTraceListener() { /* nothing special */ }

    public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message)
    {
        // some switching based on the TraceLevel, but eventually something like:
        logger.Error(message);
    }
}

コンソール アプリケーション ソリューションは、次の 3 つのプロジェクトでした。

  1. RunShipOrder - アプリケーションのエントリ ポイントであるコンソール プロジェクト
  2. ShipOrderAPI - このプロセスに関連するすべてのコードを含むクラス ライブラリ プロジェクト
  3. CodeLibrary - 多くのプロジェクトに共通するコードを含むクラス ライブラリ プロジェクト。
    • Log4netTraceListener はこのプロジェクトにあります

RunShipOrderプロジェクト内でを呼び出すことができLogManager.GetLogger("Log4netTraceListener")、期待どおりに動作します。ただし、メソッドを呼び出そうとするとTrace、例外がスローされます。クラスLogManager.GetLogger("Log4netTraceListener")内への最初の呼び出しまでさかのぼります。Log4netTraceListener

スローされるConfigurationErrorsException例外はTypeInitializationExceptionで、内部例外はです。内部例外はNullReferenceExceptionです。最も内側の例外のスタック トレースは次のとおりです。

   at log4net.Core.LoggerManager.GetLogger(Assembly repositoryAssembly, String name)
   at log4net.LogManager.GetLogger(Assembly repositoryAssembly, String name)
   at log4net.LogManager.GetLogger(String name)
   at CodeLibrary.Diagnostics.Log4netTraceListener..cctor() in Log4netTraceListener.cs:line 19

log4net コードベース内からこの例外をスローしている可能性のあるアイデアはありますか?

4

1 に答える 1

1

@drovani - 優れた説明。同じ症状が見られました。私の場合の問題は、app.config の System.Diagnostics.Trace 出力が、トレースを log4net に転送するカスタム System.Diagnostics.TraceListener 実装になるように構成され、同時に log4net.Internal を介して log4net の内部デバッグを有効にすることでした。 app.config で Debug = True (または log4net.Util.LogLog.InternalDebugging = true を介してコードで)。

静的初期化中またはロギングの直前にカスタム System.Diagnostics.TraceListener 実装で LoggerManager.GetLogger() を呼び出すと、静的初期化順序の問題が発生する可能性があります。log4net は、初期化を行っているときに何かをログに記録しようとしていますが、LoggerManager が初期化される前です。したがって、LoggerManager.GetLogger() は null 参照例外をスローします。

カスタム TraceListener では、静的プロパティを使用して、フィールドではなく最初の使用時に ILogger を初期化することで、これをある程度防ぐことができますが、ここでは注意が必要です。log4net.Util.LogLog.InternalDebugging が true の場合は、ログを記録しないか、別のメカニズムを使用してログを記録することをお勧めします。これは、推奨されるソリューションです。

log4net.Util.LogLog クラスのソースを見てください。これはデフォルトで Trace にログを記録します。アペンダー エラーなど、これによって何かがログに記録されると、デッドロック状態になります。TraceListener の実装では、実装のコンストラクターで log4net.Util.LogLog.EmitInternalMessages = false を設定し、おそらく LogLog.LogReceived イベントを処理し、それらのメッセージを別の方法でログに記録します。これに関する悲しい部分は、この設定が原因で一部のアペンダー エラーがログに記録されないことです。ここでは、log4net ソースがあなたの味方です。

パフォーマンスに大きな影響を与える非常にトリッキーにしたい場合は、メッセージをログに記録してロガーを作成する前に、log4net.Util.LogLog.InternalDebugging の設定を確認する必要があります。有効にすると、スタック トレースを取得してウォークし、log4net を呼び出す前に、log4net がスタックにないことを確認できます。log4net がスタック トレースにある場合は、OutputDebugString() を pinvoke するか、他のロギング メカニズムを使用して log4net 内部ログ出力をトレースできます。内部の log4net デバッグ メッセージを log4net にリダイレクトしたくない場合は、この優れたサイトと同様の名前の例外が発生する危険があります。

于 2015-07-20T15:46:45.067 に答える