29

ロギングの目的で例外をキャッチする必要がありますか?

public foo(..)
{{
   試す
   {{
     ..。
   } catch(Exception ex){
     Logger.Error(ex);
     投げる;
   }
}

これを各レイヤー(DataAccess、Business、WebService)に配置している場合は、例外が数回ログに記録されることを意味します。

私のレイヤーが別々のプロジェクトにあり、パブリックインターフェイスのみがそれらにtry / catchを持っている場合、そうすることは理にかなっていますか?なんで?なぜだめですか?私が使用できる別のアプローチはありますか?

4

16 に答える 16

37

絶対にありません。例外を処理するための正しい場所を見つけて(実際には、catch-and-not-rethrowなどの何かを実行して)、ログに記録する必要があります。もちろん、スタックトレース全体を含めることはできますし、含める必要がありますが、提案に従うと、コードにtry-catchブロックが散らばってしまいます。

于 2008-09-18T18:47:10.043 に答える
18

例外を変更する場合を除き、エラーを処理するレベルでのみログに記録し、エラーを再スローしないようにする必要があります。そうしないと、ログに一連の「ノイズ」があり、3 つ以上の同じメッセージが各レイヤーに 1 回記録されます。

私のベストプラクティスは次のとおりです。

  1. パブリック メソッドでのみ try/catch します (一般に、特定のエラーをトラップしている場合は、そこでチェックします)。
  2. エラーを抑制してエラー ページ/フォームにリダイレクトする直前にのみ、UI レイヤーにログインします。
于 2008-09-18T18:48:42.583 に答える
9

一般的な経験則では、実際に何かできる場合にのみ例外をキャッチします。したがって、ビジネスまたはデータ層では、次のような状況でのみ例外をキャッチします。

try
{
    this.Persist(trans);
}
catch(Exception ex)
{
    trans.Rollback();
    throw ex;
}

私のビジネス/データ層はデータを保存しようとします - 例外が生成された場合、すべてのトランザクションがロールバックされ、例外が UI 層に送信されます。

UI レイヤーでは、共通の例外ハンドラーを実装できます。

Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

次に、すべての例外を処理します。例外をログに記録し、ユーザーフレンドリーな応答を表示する場合があります。

static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
    LogException(e.Exception);
}

static void LogException(Exception ex)
{
    YYYExceptionHandling.HandleException(ex,
        YYYExceptionHandling.ExceptionPolicyType.YYY_Policy,
        YYYExceptionHandling.ExceptionPriority.Medium,
        "An error has occurred, please contact Administrator");
} 

実際の UI コードでは、別のわかりやすいメッセージを表示したり、画面を変更したりするなど、別のことを行う場合に、個々の例外をキャッチできます。

また、例外をスローするのではなく、常にエラーを処理するようにしてください。たとえば、0 で除算します。

于 2008-09-18T19:04:31.343 に答える
2

It's good practice is to translate the exceptions. Don't just log them. If you want to know the specific reason an exception was thrown, throw specific exceptions:

public void connect() throws ConnectionException {
   try {
       File conf = new File("blabla");
       ...
   } catch (FileNotFoundException ex) {
       LOGGER.error("log message", ex);
       throw new ConnectionException("The configuration file was not found", ex);
   }
}
于 2008-09-18T18:56:39.007 に答える
1

独自の例外を使用して組み込み例外をラップします。このようにして、例外をキャッチするときに既知のエラーと未知のエラーを区別できます。これは、予想されるエラーや予想外のエラーに対応するために、例外をスローする可能性が高い他のメソッドを呼び出すメソッドがある場合に役立ちます。

于 2008-09-18T18:49:23.377 に答える
1

標準の例外処理スタイルを調べたいと思うかもしれませんが、私の理解では、例外に詳細を追加できるレベル、またはユーザーに例外を提示するレベルで例外を処理します。

あなたの例では、例外をキャッチし、ログに記録し、再度スローするだけです。ログを記録するだけなら、すべてのメソッド内ではなく、1 つの try/catch で最高レベルでキャッチしてみませんか?

再度スローする前に例外に有用な情報を追加する場合は、その層でのみ処理します-通常は誰にとってもほとんど意味のない低レベルの例外テキストを超える有用な情報を持つ、作成した新しい例外で例外をラップします文脈なしで..

于 2008-09-18T18:52:40.890 に答える
1

例外が処理される場所では利用できないデータをログに記録する必要がある場合があります。その場合、その情報を取得するためだけにログを記録するのが適切です。

例 (Java 擬似コード):

public void methodWithDynamicallyGeneratedSQL() throws SQLException {
    String sql = ...; // Generate some SQL
    try {
        ... // Try running the query
    }
    catch (SQLException ex) {
        // Don't bother to log the stack trace, that will
        // be printed when the exception is handled for real
        logger.error(ex.toString()+"For SQL: '"+sql+"'");
        throw ex;  // Handle the exception long after the SQL is gone
    }
}

これは、遡及ログ (私の用語) に似ています。イベントのログをバッファリングしますが、例外がスローされるなどのトリガー イベントがない限りログを書き込みません。

于 2008-10-23T22:06:41.217 に答える
0

ティア境界でログを記録する必要があります。たとえば、ビジネス層をn層アプリケーションの物理的に分離されたマシンに展開できる場合は、この方法でログに記録してエラーをスローするのが理にかなっています。

このようにして、サーバー上に例外のログがあり、何が起こったのかを知るためにクライアントマシンを調べ回る必要はありません。

このパターンは、RemotingまたはASMXWebサービスを使用するアプリケーションのビジネス層で使用します。WCFを使用すると、ChannelDispatcherに接続されたIErrorHandler(完全に別のサブジェクト)を使用して例外をインターセプトしてログに記録できるため、try / catch/throwパターンは必要ありません。

于 2008-09-18T18:59:32.573 に答える
0

例外を処理するための戦略を策定する必要があります。キャッチアンドリスローはお勧めしません。余分なログ エントリに加えて、コードが読みにくくなります。例外のコンストラクターでログに書き込むことを検討してください。これにより、回復したい例外の try/catch が予約されます。コードを読みやすくします。予期しない例外や回復不能な例外に対処するために、プログラムの最も外側の層の近くで try/catch を使用して診断情報をログに記録することが必要な場合があります。

ところで、これが C++ の場合、catch ブロックは例外オブジェクトのコピーを作成しており、これが追加の問題の潜在的な原因となる可能性があります。例外タイプへの参照をキャッチしてみてください。

  catch (const Exception& ex) { ... }

于 2008-09-18T19:48:55.433 に答える
0

このSoftware Engineering Radio ポッドキャストは、エラー処理のベスト プラクティスの非常に優れたリファレンスです。実際には2つの講義があります。

于 2008-09-18T20:37:04.977 に答える
0

すべての例外をログに記録する必要がある場合は、素晴らしいアイデアです。とはいえ、別の理由なしにすべての例外をログに記録することは、あまり良い考えではありません。

于 2008-09-18T18:49:42.830 に答える
0

通常は UI または Web サービス コードである最上位レベルでログを記録することをお勧めします。何度もログに記録するのは一種の無駄です。また、ログを見ていると全貌が知りたくなる。

アプリケーションの 1 つで、すべてのページが BasePage オブジェクトから派生し、このオブジェクトが例外処理とエラー ログを処理します。

于 2008-09-18T18:49:51.910 に答える
0

それが唯一のことである場合、それらのクラスからtry/catchを削除し、それらの処理を担当するクラスに例外を発生させる方がよいと思います。そうすれば、例外ごとに 1 つのログのみを取得して、より明確なログを取得できます。また、スタック トレースをログに記録できるため、例外の発生場所を見逃すこともありません。

于 2008-09-18T18:50:32.143 に答える
0

私の方法は、ハンドラーでのみ例外をログに記録することです。いわば「本物の」ハンドラーです。そうしないと、ログが非常に読みにくくなり、コードの構造が崩れます。

于 2008-09-18T18:53:01.387 に答える
0

それは例外に依存します。これが実際に発生しない場合は、間違いなくログに記録します。反対に、この例外が予想される場合は、アプリケーションの設計について考える必要があります。

いずれにせよ、少なくとも、再スロー、キャッチ、またはログに記録する例外を指定するようにしてください。

public foo(..)
{
   try
   {
     ...
   }
   catch (NullReferenceException ex) {
     DoSmth(e);
   }
   catch (ArgumentExcetion ex) {
     DoSmth(e);
   }
   catch (Exception ex) {
     DoSmth(e);
   }
}
于 2008-09-18T18:54:56.220 に答える