多層アーキテクチャ:エラー​​ロギング\処理を実装する場所


17

現在、多層アーキテクチャを使用して大規模なサブシステムをリファクタリングしており、効果的なエラーログ処理戦略の設計に苦労しています。

私のアーキテクチャは、次の3つのレイヤーで構成されているとしましょう。

  • パブリックインターフェイス(IE MVCコントローラー)
  • ドメイン層
  • データアクセス層

私の混乱の原因は、エラーロギング\処理を実装する場所です。

  1. 最も簡単な解決策は、ログをトップレベル(IE Public Interface \ MVC Controller)に実装することです。しかし、これは間違っていると感じます。これは、異なるレイヤーを介して例外をバブリングし、ログに記録することを意味するためです。そのソースで例外をログに記録するのではなく。

  2. 私が最も多くの情報を持っているので、そのソースで例外をログに記録することは明らかに最適なソリューションです。これに関する私の問題は、すべての例外をキャッチせずにソースですべての例外をキャッチできないことであり、ドメイン/パブリックインターフェイスレイヤーでは、これはすでに下のレイヤーでキャッチされ、ログに記録され、再スローされた例外をキャッチすることになります。

  3. もう1つの可能な戦略は、#1と#2の組み合わせです。これにより、スローされる可能性が最も高いレイヤーで特定の例外をキャッチし(SqlExceptionsつまり、データアクセスレイヤーでキャッチ、ロギング、再スロー)、トップレベルでキャッチされなかった例外をログに記録します。しかし、これはまた、すでにログに記録されたエラーと処理されていないエラーを区別できないため、トップレベルですべての例外をキャッチして再ログする必要があります。

さて、これは明らかにほとんどのソフトウェアアプリケーションの問題であるため、例外がソースで捕捉され、一度ログに記録されるこの問題の標準的な解決策が必要です。しかし、自分でこれを行う方法がわかりません。

この質問のタイトルは「多層アプリケーションでの例外ロギング」に非常に似ていますが、その投稿の回答には詳細が欠けており、私の質問に答えるには不十分です。


1
私が時々使うアプローチの1つは、独自のException(またはRuntimeException)サブクラスを作成し、ネストされた例外として元の例外を含めてスローすることです。もちろん、上位レベルで例外をキャプチャする場合、例外のタイプを確認する必要があることを意味します(自分の例外は単にスローされ、他の例外はログに記録され、例外の新しいインスタンスに含まれます)。しかし、私は長い間ソロで仕事をしているので、「公式」なアドバイスはできません。
SJuan76

4
The easiest solution would be to implement the logging at the top level- これを行う。ソースで例外をログに記録することはお勧めできません。これを実行したすべてのアプリケーションは、デバッグするPITAでした。例外を処理するのは呼び出し元の責任である必要があります。
ジャスティン

特定の実装テクニック/言語を念頭に置いているようです。そうでない場合、「記録された例外は、そうでないものと区別できません」という文は理解しにくいです。もっと文脈を教えてください。
ブルームフォンデル

@Vroomfondel-そのとおりです。私はC#を使用しており、各レイヤーでコードをラップすると、各レイヤーでtry{ ... } catch(Exception ex) { Log(ex); }同じ例外がログに記録されます。(コードベースのすべてのレイヤーですべての例外をキャッチすることも、かなり悪い習慣のようです。)
KidCode

回答:


18

ご質問へ:

最も簡単な解決策は、ロギングをトップレベルで実装することです

例外をトップレベルにバブルすることは、絶対に正しいもっともらしいアプローチです。上位層のメソッドはいずれも、失敗後に何らかのプロセスを継続しようとしませんが、通常は成功しません。また、設備の整った例外には、ロギングに必要なすべての情報が含まれています。また、例外について何もしないと、コードをクリーンに保ち、失敗ではなくメインタスクに集中できます。

私が最も多くの情報を持っているので、そのソースで例外をログに記録することは明らかに最適なソリューションです。

それは半分正しいです。はい、ほとんどの有用な情報が利用できます。しかし、すぐにログに記録するのではなく、例外オブジェクトにすべてを入れることをお勧めします(まだ存在していない場合)。低レベルでログを記録する場合、例外をスローして、ジョブを完了していないことを発信者に伝える必要があります。これにより、同じイベントの複数のログが作成されます。

例外

私の主なガイドラインは、トップレベルでのみ例外をキャッチして記録することです。そして、以下のすべてのレイヤーは、必要なすべての障害情報が最上位に転送されることを確認する必要があります。Javaなどの単一プロセスアプリケーション内では、これはほとんどの場合、トップレベルの外部で試行/キャッチまたはログ記録を行わないことを意味します。

場合によっては、例外がスローされたときに実行されたSQLステートメントやパラメーターなど、元の例外では使用できないコンテキスト情報を例外ログに含める必要があります。その後、元の例外をキャッチして、元の例外とコンテキストを含む新しい例外を再スローできます。

もちろん、実生活は時々干渉します:

  • Javaでは、いくつかの固定メソッドシグネチャに従うためだけに、例外をキャッチして別の例外タイプにラップする必要がある場合があります。ただし、例外を再スローする場合は、再スローされた例外に、後でロギングするために必要なすべての情報が含まれていることを確認してください。

  • プロセス間境界を越える場合、多くの場合、技術的にはスタックトレースを含む完全な例外オブジェクトを転送できません。そしてもちろん、接続が失われる可能性があります。そのため、サービスが例外をログに記録し、可能な限り多くの障害情報を回線を介してクライアントに送信するように努める必要があります。サービスは、失敗応答を受信するか、接続が切断された場合にタイムアウトに陥ることにより、クライアントが失敗通知を受け取ることを確認する必要があります。これにより、通常、同じ障害が2回記録されます。1回はサービス内(詳細)で、もう1回はクライアントのトップレベルで記録されます。

ロギング

例外ロギングだけでなく、一般的なロギングに関する文章をいくつか追加します。

例外的な状況に加えて、アプリケーションの重要なアクティビティもログに記録する必要があります。そのため、ロギングフレームワークを使用します。

ログレベルに注意してください(デバッグ情報と重大なエラーに応じて異なるフラグが付けられていないログを読むのは苦痛です!)。一般的なログレベルは次のとおりです。

  • エラー:一部の機能は回復不能に失敗しました。これは必ずしもプログラム全体がクラッシュしたという意味ではありませんが、一部のタスクを完了できませんでした。通常、障害を説明する例外オブジェクトがあります。
  • 警告:奇妙なことが起こりましたが、タスクが失敗することはありませんでした(奇妙な構成が検出された、一時的な接続の破損により再試行が発生したなど)
  • 情報:重要なプログラムアクションをローカルシステム管理者に伝えたい(構成とソフトウェアバージョンでサービスを開始し、データファイルをデータベースにインポートし、ユーザーがシステムにログインすると、アイデアが得られる)。
  • デバッグ:開発者が問題をデバッグするときに見たいもの(ただし、このバグまたは特定のバグの場合に本当に必要なものを事前に知ることはできません-予見できる場合は、バグを修正します) )。常に役立つことの1つは、外部インターフェイスでアクティビティを記録することです。

本番環境では、ログレベルをINFOに設定します。結果は、システム管理者が何が起こっているかを知るのに役立つはずです。ログ内のすべてのエラーと警告の半分について、支援またはバグ修正のために彼に電話することを期待してください。

実際のデバッグセッション中にのみDEBUGレベルを有効にします。

ログエントリを適切なカテゴリにグループ化します(たとえば、エントリを生成するコードの完全修飾クラス名によって)。プログラムの特定の部分のデバッグログを有効にできます。


このような詳細な回答をありがとう、ロギングの部分にも感謝しています。
KidCode

-1

私は下票を引き受けていますが、手足に出て、これに同意できるかどうかわからないと言います。

例外をバブリングし、それらを再度ログに記録することはほとんどありませんが、余分な労力を費やしてもほとんど利点はありません。ソースで例外をキャッチし(はい、最も簡単です)、ログに記録しますが、例外を再スローせず、呼び出し元に「エラー」を報告するだけです。「-1」、ヌル、空の文字列、列挙型など。呼び出し元は、呼び出しが失敗したことのみを知る必要があり、恐ろしい詳細はほとんどありません。そして、それらはあなたのログにありますよね?まれに、発信者が詳細を必要とする場合、先に進んでバブルアップしますが、自動の考えられないデフォルトとしてではありません。


3
戻り値でエラーを報告する際の問題は次のとおりです。1.呼び出し元が失敗を気にする場合、特別な値を確認する必要があります。しかし、待ってください、nullそれとも空の文字列ですか?-1または負の数ですか?2.発信者が気にしない(チェックしない)場合、これは元の原因とは関係のないフォローアップエラーにつながりNullPointerExceptionます。さらに悪いことには、間違った値で計算が続行されます。3.呼び出し側は気にするが、プログラマーがこのメソッドが失敗することを考えない場合、コンパイラーは彼に思い出させません。例外にはこの問題はありません。キャッチするか、再スローします。
siegi

1
申し訳ありませんが、私はそれを支持しなければなりませんでした。あなたが説明するアプローチ(例外を特別な戻り値に置き換える)は、C言語が生まれた1970年代の最先端であり、現代の言語に例外がある理由はたくさんあります。例外を適切に使用すると、堅牢なコードを簡単に記述できます。そして、「例外をバブリングする[...]は余分な努力をする[...]」というのはまったく間違っています。例外については何もしないでください。
ラルフクレバーホフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.