「ログアンドスロー」がアンチパターンと見なされるのはなぜですか?[閉まっている]


89

この質問は、周りの議論によって引き起こされました 、私が良い答えを受け取らなかったこの記事

他の方法で処理できない場合、例外をログに記録してから再スローする(もちろん元のスタックトレースを保持する)のはなぜ悪い考えですか?


回答:


129

答えは主に、それを処理できないのになぜそれを捕まえているのかということだと思います。ログに値すると感じた場合は、処理できる人(または処理する以外に選択肢がない人)にログを記録させてはどうでしょうか。

それをキャッチしてログに記録し、再スローすると、アップストリームコードが例外をログに記録したことを知る方法がないため、同じ例外が2回ログに記録される可能性があります。さらに悪いことに、すべてのアップストリームコードがこの同じパターンに従っている場合、例外は、キャッチしてログに記録してから再度スローすることを決定したコードのレベルごとに1回、任意の回数ログに記録される可能性があります。

また、例外のスローとキャッチは比較的コストのかかる操作であるため、このキャッチと再スローはすべてランタイムパフォーマンスに役立たないと主張する人もいるかもしれません。また、簡潔さや保守性の観点からもコードを支援するものではありません。


詳細については、Jeffの回答に対するコメントを参照してください
Manu 2011

8
例外をログに記録して再スローする理由は、理由を絞り込んで特定のメッセージをログに記録するためです。
Mike Argyriou 2014

12
回答:スタックトレースの別のポイントでは利用できない、スタックの現在のポイントで利用できる有用なデバッグ情報がある可能性があります
rtconner 2017

新しい例外がより多くの情報またはより具体的に役立つ場合は、キャッチと再スローが役立つことがあります。
borjab 2017年

1
@rtconnerがコメントした内容に費やすには、非同期コードでは、キャッチャーにスローアーが使用できるコンテキストがない可能性があります。
NirAlfasi20年

55

ログアンドスローは、例外をキャッチして再スローするエンティティが、少なくとも最も望ましい方法ではなく、コールスタックの上位にログに記録されない情報が含まれていると信じる理由がある場合に適したパターンです。これが発生する可能性のあるいくつかの理由:

  1. 例外は、アプリケーション層の境界でキャッチおよび再スローされる可能性があり、特権情報が含まれる可能性があります。データベース層が例外を許可するのは悪いことです。たとえば、「重複するキー 'fnord'をフィールド 'users'に追加しようとしました」と言って、外部のアプリケーション層に到達します(これにより、ユーザーに公開される可能性があります)。データベースの内部がそのような例外をスローし、アプリケーションインターフェイスがそれをキャッチし、安全にログに記録し、やや説明の少ない例外を再スローするのに役立つ可能性があります。
  2. 例外は、外層がロギングなしで処理することを期待している可能性が高いものですが、内層は外層が知らないことを知っている可能性があり、ロギングが役立つ可能性があることを示唆しています。大まかな例として、中間のアプリケーション層は、あるサーバーへの接続を試行し、それが機能しない場合は別のサーバーを試行するようにプログラムされている場合があります。サーバーがメンテナンスのためにダウンしているときに、アプリケーションのログを「接続に失敗しました」というメッセージで溢れさせることは、特に、アプリケーションの観点からはすべてが正常に機能したため、役に立たない場合があります。接続障害に関する情報をサーバーに関連付けられたロギングリソースに転送すると便利な場合があります。これにより、ログをフィルタリングして、接続の試行ごとのログではなく、サーバーがいつ上下したかに関するレポートを生成できます。 。

4
#1は確かに賢明な一般的なユースケースですが、OPは明示的に「それを再スローする(もちろん元のスタックトレースを保持する)」ことを求めたため、#1は正しい答えではありません。
Geoffrey Zheng 2015年

@GeoffreyZheng:それは、元のスタックトレースを安全にログに記録することが「保存」としてカウントされるかどうかによって異なります。
スーパーキャット2015年

3
#1に関して:e.getMessage()実行時例外にはあらゆる種類の機密情報が含まれている可能性があるため、例外コンテンツの公開(UIでの/ stacktraceの表示やREST応答としての送信など)は脆弱性自体として扱う必要があります。#2に関して:クライアントに知らせたいすべての情報(+根本原因)を追加して例外を再スローできます。何もログに記録する必要はありません。
NikitaBosik18年

@NikitaBosik:例外をクライアント側で公開するかどうかに関係なく、公開するアプリケーションは十分に一般的であるため、「多層防御」の原則により、例外メッセージから機密情報を削除する必要があります。さらに、外部レイヤーが特定のタイプの例外をログに記録したり、関心のある可能性のある外部エンティティに情報を転送したりせずに破棄することを期待していない場合、中間レイヤーに外部レイヤーが無視する情報を追加しても役に立ちません。何でも。
スーパーキャット2018年

20

最も単純な理由は、通常、単一のトップレベルハンドラーがこれを実行するため、この例外処理でコードを汚染する必要がないことだと思います。

横断的関心事の議論は、基本的に、あなたに関係のないエラーを処理するのは時間の無駄であるということです。適切なハンドラーが見つかるまで、エラーがコールスタックをバブルアップさせる方がはるかに優れています。

私の意見では、例外をキャッチする必要があるのは、結果を使って何か役立つことができるときだけです。単にログを記録するためにキャッチすることは、その作業をさらに一元化できるため、役に立ちません。


2
私はあなたがあなたのためにこれをする単一のトップレベルのハンドラーを持つべきであることに同意します。しかし、私の意見では、そのトップレベルのハンドラーは「ログアンドスロー」である必要があります。ですから、議論は「ログに記録して投げる」という点であり、それを行うかどうかではありませんか?!?
マヌー2011

@Manu、ポイントは、それが単一のハンドラー(集中型)の場合は問題ないということだと思います。コードを複製している場合、それは問題ありません。それ以上のものはないと思います!
ジェフ・フォスター

5
@ Manu-その場合、トップレベルのハンドラーは何をスローしますか?スローできるものがある場合、それは実際にはトップレベルのハンドラーではないように思われます。そして、ランタイム環境自体に例外を再スローしたくないことは間違いありません。これにより、ほとんどのアプリケーションがクラッシュ停止します。
aroth 2011

1
@aroth:なるほど、あなたが言っているのは、「ログとハンドル」(トップレベルのハンドラーの場合)または「ログとスローを行わない(またはそれ以外の場合は処理)」のいずれかです。それを指摘してくれてありがとう。
マヌー2011

9

IMOのログとスローは、驚き最小の原則の明らかな違反です。

例外がコールスタックのさらに上で適切に処理される場合、エラーログエントリの価値はまったくない可能性があります。そして、エラーログエントリを見つけるのは混乱します。


エラー以外のログはどうですか?
Su Zhang

6
@SuZhangあなたの質問がよくわかりません。エラーがなければ、投げるものは何もありません。もちろん、エラー以外のログを書き込むことはできますし、書き込む必要があります。
Bastian Voigt 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.