アプリケーションのどこかで例外がスローされたことを検出するにはどうすればよいですか?
Java デスクトップアプリケーションのどこかで例外がスローされるたびに、魔法のように自分自身に電子メールを送信しようとしています。そうすることで、より積極的に行動できるようになると思います。
例外が発生するたびに、明示的にログに記録して自分自身に通知できることはわかっていますが、どこでもそれを行う必要があり、いくつか見逃す可能性があります。
助言がありますか?
あなたはおそらくどんな例外でもメールしたくないでしょう。JDK には、正常に動作するために実際に例外に依存しているコードが多数あります。あなたがもっと興味を持っていると思うのは、キャッチされていない例外です。例外をキャッチしている場合は、そこで通知を処理する必要があります。
デスクトップ アプリでは、イベント ディスパッチ スレッド(EDT) と EDT の外側の2 つの場所でこれを考慮する必要があります。グローバルに実装するクラスjava.util.Thread.UncaughtExceptionHandler
を登録し、 経由で登録できますjava.util.Thread.setDefaultUncaughtExceptionHandler
。これは、例外がスタックの一番下に到達し、スレッドの現在のスレッド インスタンスまたは ThreadGroup にハンドラーが設定されていない場合に呼び出されます。
EDT には、例外を処理するための別のフックがあります。システム プロパティ'sun.awt.exception.handler'
は、ゼロ引数コンストラクターを持つクラスの完全修飾クラス名で登録する必要があります。このクラスには、作業を行うインスタンス メソッド handle( Throwable
) が必要です。戻り値の型は問題ではなく、毎回新しいインスタンスが作成されるため、状態を維持する必要はありません。
したがって、サンプルで例外が発生したスレッドを気にしない場合は、次のようになります。
class ExceptionHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
handle(e);
}
public void handle(Throwable throwable) {
try {
// insert your e-mail code here
} catch (Throwable t) {
// don't let the exception get thrown out, will cause infinite looping!
}
}
public static void registerExceptionHandler() {
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
System.setProperty("sun.awt.exception.handler", ExceptionHandler.class.getName());
}
}
このクラスをランダムなパッケージに追加してからregisterExceptionHandler
メソッドを呼び出すと、準備が整います。
Java 1.5 の新しいデバッグ フックを使用すると、これを行うことができます。たとえば、デバッガーで「任意の例外でブレーク」を有効にします。
Thread.UncaughtExceptionHandlerを確認してください。スレッドごとに設定することも、VM 全体のデフォルトを設定することもできます。
これは、少なくとも見逃したものをキャッチするのに役立ちます.
私の現在のプロジェクトでは、エラー検出に関して同様の要件に直面しました。この目的のために、次のアプローチを適用しました。アプリ全体のログ記録に log4j を使用し、例外がキャッチされた場合はどこでも標準的なことを行います log.error("Error's description goes here", e);
: 「ログ」の)。エラーを検出するために、log4j AppenderSkeleton クラスを拡張する独自の Appender を使用します。
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
public class ErrorsDetectingAppender extends AppenderSkeleton {
private static boolean errorsOccured = false;
public static boolean errorsOccured() {
return errorsOccured;
}
public ErrorsDetectingAppender() {
super();
}
@Override
public void close() {
// TODO Auto-generated method stub
}
@Override
public boolean requiresLayout() {
return false;
}
@Override
protected void append(LoggingEvent event) {
if (event.getLevel().toString().toLowerCase().equals("error")) {
System.out.println("-----------------Errors detected");
this.errorsOccured = true;
}
}
}
log4j 構成ファイルには、新しいアペンダーの定義と、選択したロガー (私の場合はルート) へのアタッチメントを含める必要があります。
log4j.rootLogger = OTHER_APPENDERS, ED
log4j.appender.ED=com.your.package.ErrorsDetectingAppender
プログラムの実行フローの重要なポイントで ErrorsDetectingAppender の errorsOccured() メソッドを呼び出すか、append() メソッドの if ブロックに機能を追加して即座に対応することができます。このアプローチはセマンティクスと一致しています。つまり、エラーと見なしてログに記録するものが検出されます。後で選択したエラーをそれほど重要ではないと考える場合は、ログ レベルを log.warn() に変更するだけで、レポートは送信されません。
Java 1.3/1.4 を使用している場合、Thread.UncaughtExceptionHandler は使用できません。この場合、AOP に基づくソリューションを使用して、例外がスローされたときにいくつかのコードをトリガーできます。春やアスペクトJが役立つかもしれません。
Springなどの Web フレームワークを使用している場合は、web.xml でページに委任し、コントローラーを使用して電子メールを送信できます。例えば:
web.xml で:
<error-page>
<error-code>500</error-code>
<location>/error/500.htm</location>
</error-page>
次に、/error/500.htm をコントローラーとして定義します。パラメータ javax.servlet.error.exception から例外にアクセスできます。
Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
通常の Java プログラムを実行しているだけなら、 public static void main(String[] args) { try { ... } catch (Exception e) {} } で行き詰まっていると思います。
この場合、アプリケーションですべてのクラスローディングを処理するカスタム クラスローダーを記述し、例外クラスが要求されるたびに、要求された例外クラスをラップするクラスを返すことが最善の策であると思います。このラッパーは、ラップされた例外を呼び出しますが、例外イベントもログに記録します。
OutOfMemoryError や StackOverflow などの実行時例外が発生している場合、メールを送信できない場合があります。ほとんどの場合、別のプロセスを生成し、それによってスローされた例外をキャッチする必要があります (上記のさまざまな手法を使用)。
例外ではなく、キャッチされていない例外を意味していると思います。
その場合は、Sun Web サイトのこの記事にいくつかのアイデアがあります。トップレベルのメソッドをブロックでラップし、try-catch
他のスレッドを処理するために追加の作業を行う必要があります。