web-dev-qa-db-ja.com

スタックトレースのない例外-どのように?

未処理の例外をアプリドメインレベルで(Log4net経由で)ログに記録するサービスがあります。

ログに記録しました:

2014-01-28 16:49:19,636エラー[49] FeedWrapperService-未処理のSystem.NullReferenceException:オブジェクト参照がオブジェクトのインスタンスに設定されていません。

この例外にはスタックトレースがありません。例外オブジェクトにいくつかのクレイジーなことをせずに、それはどのように可能ですか?

私たちの取り扱いコード:

AppDomain.CurrentDomain.UnhandledException += LogAnyExceptions;

private void LogAnyExceptions(object sender, UnhandledExceptionEventArgs e)
{
    log.Error("unhandled", (Exception)e.ExceptionObject);
    throw (Exception)e.ExceptionObject;
}

とにかくAppDomainがプロセスとともにダウンするため、ここでの再スローは無意味であると私は思いますが、それが私たちの状況に影響を与えるとは思いません。

Windowsアプリケーションイベントビューアにも、このnull ref例外のみが表示され、トレースは表示されません。

例外ハンドラのログをテストしましたが、スタックトレースと内部例外が正常にログに記録されます。コードによってスローされた場合、スタックトレースが表示されます。サードパーティのc#ライブラリによってスローされた場合も、少なくとも1つのメソッドのスタックトレースが表示されます(再スローされた例外であるかどうかは関係ありません)。ここでは、スタックトレースのないマネージド例外が表示されます。これがどのように可能かわかりません。

逆コンパイルされたサードパーティライブラリを見ると、アンマネージコードと通信し、この例外を発生させたイベントはアンマネージランドで発生する可能性がありますが、このような状況でスタックトレースなしでマネージnull参照例外が発生する可能性はありますか?

この問題の原因は断続的です。このコードを本番環境で数か月実行していて、これが1回実行されるのを確認しました。それはかなり気紛れです。

この種の問題の原因となるシステムは、問題に対処して安全かつ自動的に再起動できるように、子プロセスにプッシュする必要があるというのが一般的なコンセンサスですが、何が起こっているのかを知っておくと便利です。

編集して以下のコメント情報を含めます:

スタックトレースがnullまたは空であるため、私の例外は標準の再スローではありません。再スローメソッドの名前は含まれていません。さらに掘り下げてみると、Exceptionクラスはシリアル化された情報から構築でき、シリアル化された情報にはスタックトレースのnull文字列が含まれている可能性があり、他のエラーを発生させることなく作成できる可能性があります。そこから来たのかもしれませんが、どうやって生まれたのかわかりません。

17
Skym

例外を受信して​​いるが、対応するスタックトレースがない場合、ある時点で、例外ハンドラーが例外を評価し、誤って再スローしている可能性があります。たとえば、throw ex;を実行している場合は、そのポイントにつながったスタックトレースを食べます。既存のコールスタックを保持するには、単にthrow;例外のスローのベストプラクティス

C#の方法は、Java言語の規則の反対であり、throw ex; Java参照: ベストプラクティス:キャッチと再スローJava例外

11
shooley

私はカスタム例外を使用して例外を管理することを好みます。独自の例外を使用している場合は、それらを定義したクラスに移動して、スタックトレースをオーバーライドできます。例えば:

public class YourCustomException: Exception
{
    public YourCustomException() : base() { } //constructor

    public override string StackTrace 
    {
        get { return "Message instead stacktrace"; }
    }
}
6
Daniel Vega