Comment puis-je détecter quand une Exception a été levée globalement en Java?

Comment puis-je détecter quand une Exception a été levée n'importe où dans mon application?

J'essaie de m'envoyer automatiquement un e-mail chaque fois qu'une exception est levée n'importe où dans mon Application de bureau Java. Je pense que de cette façon, je peux être plus proactif.

Je sais que je pourrais simplement me connecter explicitement et me notifier chaque fois qu'une exception se produit, mais je devrais le faire partout et je pourrais(plus probablement) en manquer un couple.

Des suggestions?

24
demandé sur Allain Lalonde 2008-09-16 22:07:34

9 réponses

Vous ne voulez probablement pas envoyer de courrier sur une exception. Il y a beaucoup de code dans le JDK qui dépendent actaully des exceptions pour fonctionner normalement. Ce que je suppose que vous êtes plus inerested Dans sont des exceptions non capturées. Si vous attrapez les exceptions, vous devez gérer les notifications là-bas.

Dans une application de bureau, Il y a deux endroits pour s'inquiéter à ce sujet, dans le event-dispatch-thread (EDT) et en dehors de L'EDT. Globaly vous pouvez enregistrer une classe implémentant java.util.Thread.UncaughtExceptionHandler et l'enregistrer via java.util.Thread.setDefaultUncaughtExceptionHandler. Cela sera appelé si une exception descend au bas de la pile et que le thread n'a pas de gestionnaire défini sur l'instance de thread en cours sur le thread ou le ThreadGroup.

L'EDT a un crochet différent pour gérer les exceptions. Une propriété système 'sun.awt.exception.handler' doit être registerd avec le nom de classe complet D'une classe avec un constructeur d'argument zéro. Cette classe a besoin d'un handle de méthode d'instance(Throwable) qui fait votre travail. Le type de retour n'a pas d'importance, et comme une nouvelle instance est créée à chaque fois, ne comptez pas sur le maintien de l'état.

Donc, si vous ne vous souciez pas de quel thread l'exception s'est produite dans un échantillon peut ressembler à ceci:

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());
  }
}

Ajoutez cette classe dans un paquet aléatoire, puis appelez la méthode registerExceptionHandler et vous devriez être prêt à partir.

34
répondu shemnon 2016-03-26 00:02:09

Les nouveaux crochets de débogage dans Java 1.5 vous permettent de le faire. Il permet par exemple "pause" aucune exception" dans les débogueurs.

Voici le Javadoc spécifique dont vous avez besoin.

5
répondu Jason Cohen 2008-09-16 18:12:14

Vérifier Thread.UncaughtExceptionHandler . Vous pouvez le définir par thread ou par défaut pour l'ensemble de la machine virtuelle.

Cela vous aiderait au moins à attraper ceux que vous manquez.

4
répondu Justin Rudd 2008-09-16 18:12:45

Si vous utilisez java 1.3/1.4, Fil.UncaughtExceptionHandler n'est pas disponible. Dans ce cas, vous pouvez utiliser une solution basée sur AOP pour déclencher du code lorsqu'une exception est levée. Spring et / ou aspectJ pourraient être utiles.

1
répondu Alexandre Victoor 2008-09-16 20:27:51

Dans mon projet actuel, j'ai fait face à la même exigence concernant la détection des erreurs. Pour ce faire, j'ai appliqué l'approche suivante: j'utilise log4j pour me connecter à travers mon application, et partout, où l'exception est détectée, je fais la chose standard: log.error("Error's description goes here", e);, Où e est l'Exception levée (voir la documentation log4j pour plus de détails sur l'initialisation du "journal"). Afin de détecter l'erreur, j'utilise mon propre Appender, qui étend le log4j AppenderSkeleton classe:

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;
        }
    }
}

Le fichier de configuration log4j doit simplement contenir une définition du Nouvel appender et son attachement à l'enregistreur sélectionné (root dans mon cas):

log4j.rootLogger = OTHER_APPENDERS, ED
log4j.appender.ED=com.your.package.ErrorsDetectingAppender

Vous pouvez appeler la méthode errorsOccured () de ErrorsDetectingAppender à un moment significatif du flux d'exécution de vos programmes ou réagir immédiatement en ajoutant des fonctionnalités au bloc if dans la méthode append (). Cette approche est cohérente avec la sémantique: les choses que vous considérez comme des erreurs et des journaux comme tels, sont détectés. Si vous considérez plus tard que les erreurs sélectionnées ne sont pas si importantes, vous changez simplement le niveau de journalisation pour log.warn () et report ne seront pas envoyés.

1
répondu Alex Fedulov 2012-03-08 08:57:54

Dans ce cas, je pense que votre meilleur pari pourrait être d'écrire un classloader personnalisé pour gérer tout le chargement de classes dans votre application, et chaque fois qu'une classe d'exception est demandée, vous renvoyez une classe qui enveloppe la classe d'exception demandée. Ce wrapper appelle à l'exception encapsulée mais enregistre également l'événement d'exception.

0
répondu toluju 2008-09-16 18:11:58

Si vous utilisez un framework web tel que Spring , Vous pouvez déléguer dans votre site web.xml à une page, puis utilisez le contrôleur pour envoyer l'e-mail. Par exemple:

Dans le web.xml:

<error-page>
  <error-code>500</error-code>
  <location>/error/500.htm</location>
</error-page>

Ensuite, définissez / error / 500.htm en tant que contrôleur. Vous pouvez accéder à l'exception du paramètre javax.servlet.erreur.exception:

Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");

Si vous exécutez juste un programme Java régulier, alors j'imagine que vous êtes coincé avec public static void main(String [] args) { try { ... } attraper (Exception e) {}}

0
répondu Mat Mannion 2008-09-16 18:13:46

Je suppose que vous ne veux pas dire tout Exception, mais plutôt l' les Exception.

Si c'est le cas Cet article sur le site Web du Sun a quelques idées. Vous devez envelopper votre méthode de niveau supérieur dans un bloc try-catch et également faire un travail supplémentaire pour gérer d'autres Threads.

0
répondu Dave Webb 2008-09-16 18:13:56

L'envoi d'un e-mail peut ne pas être possible si vous obtenez une exception d'exécution comme OutOfMemoryError ou StackOverflow. Très probablement, vous devrez générer un autre processus et attraper toutes les exceptions lancées par celui-ci (avec les différentes techniques mentionnées ci-dessus).

0
répondu Nik 2008-09-16 18:27:23