2008-09-16 5 views
24

¿Cómo puedo detectar cuándo se ha lanzado una excepción en mi aplicación?¿Cómo puedo detectar cuándo se ha lanzado una excepción globalmente en Java?

Intento enviarme automáticamente un correo electrónico cada vez que se lanza una excepción en mi aplicación Java Desktop. Me imagino que puedo ser más proactivo.

Sé que podría simplemente registrarme y notificarme explícitamente cada vez que ocurra una excepción, pero tendría que hacerlo en todas partes y es posible que (es más probable que) extrañe un par.

¿Alguna sugerencia?

+0

Al trabajar con Java 7 o posterior, es posible que desee comprobar las respuestas a http://stackoverflow.com/questions/95767/how-can-i-catch-awt-thread-exceptions-in-java?lq=1 – Suma

Respuesta

34

Es posible que no desee enviar una excepción. Hay muchos códigos en el JDK que dependen de las excepciones para funcionar normalmente. En lo que supongo que estás más interesado son las excepciones no detectadas. Si está capturando las excepciones, debe manejar las notificaciones allí.

En una aplicación de escritorio hay dos lugares de qué preocuparse, en el (EDT) y fuera del EDT. Globaly puede registrar una clase implementando java.util.Thread.UncaughtExceptionHandler y registrarla a través del java.util.Thread.setDefaultUncaughtExceptionHandler. Se llamará a esto si una excepción llega al final de la pila y no se ha establecido un manejador en la instancia actual de la cadena o en el ThreadGroup.

El EDT tiene un gancho diferente para manejar excepciones. Una propiedad del sistema 'sun.awt.exception.handler' debe estar registrada con el nombre de clase completamente calificado de una clase con un constructor de argumento cero. Esta clase necesita un identificador de método de instancia (Throwable) que haga su trabajo. El tipo de devolución no importa, y dado que se crea una nueva instancia cada vez, no cuente con mantener el estado.

Así que si no le importa lo que el hilo se produjo la excepción en una muestra puede tener este aspecto:

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

Añadir esta clase en algún paquete al azar, y luego llamar al método registerExceptionHandler y que debe estar listo ir.

+0

Nice! Gracias por el código. –

+2

¿Por qué necesita System.setProperty última línea ("sun.awt.exception.handler", ExceptionHandler.class.getName()); Está funcionando sin esta línea. Y sun.awt podría ser específico para la implementación del sol, supongo. – feiroox

+1

En caso de que la excepción se arroje al lado del subproceso de envío de evento. El Swing/AWT EDT tiene su propio receptor de excepción en la raíz de su hilo y este es el enganche. – shemnon

0

En este caso, creo que su mejor opción es escribir un cargador de clases personalizado para manejar toda la carga de clases en su aplicación, y siempre que solicite una clase de excepción devuelva una clase que envuelva la clase de excepción solicitada. Este contenedor llama a la excepción envuelta pero también registra el evento de excepción.

5

Los nuevos ganchos de depuración en Java 1.5 le permiten hacer esto. Permite, p. "romper con cualquier excepción" en los depuradores.

Here's the specific Javadoc usted necesita.

4

Echa un vistazo Thread.UncaughtExceptionHandler. Puede establecerlo por hilo o por defecto para toda la máquina virtual.

Esto al menos te ayudaría a atrapar los que extrañas.

0

Si estás utilizando un framework de desarrollo web como Spring a continuación, puede delegar en su web.xml para una página y luego utilizar el controlador para enviar el correo electrónico. Por ejemplo:

En web.xml:

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

continuación, definir /error/500.htm como un controlador. Se puede acceder a la excepción del parámetro javax.servlet.error.exception:

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

Si sólo está ejecutando un programa regular de Java, entonces me imagino que está pegado con public static void main (String [ ] args) {try {...} catch (Exception e) {}}

+0

Ese ejemplo se aplica a cualquier "aplicación web" y no tiene nada que ver con Spring o web frameworks. También se aplica solamente a las excepciones no capturadas que suben a la clase servlet base, haciendo así que el estado HTTP 500 - que puede ser lo que se quiere (o no). – Cheekysoft

+0

Ah, gracias - sólo tengo experiencia con la primavera, así que no quiero hablar fuera de turno :) –

0

asumo que no quieres decir cualquier excepción, sino cualquier no detectada Excepción.

Si este es el caso this article on the Sun Website tiene algunas ideas. Debe envolver su método de nivel superior en un bloque try-catch y también hacer un trabajo extra para manejar otros subprocesos.

0

Enviar un correo electrónico puede no ser posible si obtiene una excepción de tiempo de ejecución como OutOfMemoryError o StackOverflow. Lo más probable es que tenga que engendrar otro proceso y atrapar las excepciones lanzadas por él (con las diversas técnicas mencionadas anteriormente).

+0

Vale la pena notar la diferencia entre Errores y Excepciones. Ambos son Throwable, pero los errores no son excepciones ya que son hermanos. – Cheekysoft

1

Si está utilizando Java 1.3/1.4, Thread.UncaughtExceptionHandler no está disponible. En este caso, puede usar una solución basada en AOP para activar algún código cuando se lanza una excepción. Spring y/o aspectJ pueden ser útiles.

1

En mi proyecto en el que se enfrentaron al requisito similar en cuanto a la detección de errores. Para esto he aplicado el siguiente enfoque: Consumo log4j para iniciar sesión a través de mi aplicación, y en todas partes, donde se detecta la excepción que hago lo estándar: log.error("Error's description goes here", e);, donde se está lanzando e la excepción (véase la documentación log4j para obtener más información con respecto a la inicialización del "registro"). Con el fin de detectar el error, utilizo mi propia Appender de, la cual se extiende el log4j clase AppenderSkeleton:

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

El archivo de configuración de log4j tiene que sólo contiene una definición de la nueva appender y su attachement al registrador seleccionado (raíces en mi caso):

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

Usted puede llamar al método errorsOccured() de la ErrorsDetectingAppender en algún momento significativo en el flujo de ejecución de sus programas o reaccionar Inmediatamente añadiendo funcionalidad al caso de bloque en el modo de adición() método . Este enfoque es coherente con la semántica: se detectan las cosas que se consideran errores y se registran como tales. Si luego considera que los errores seleccionados no son tan importantes, simplemente cambie el nivel de registro a log.warn() y no se enviará el informe.

Cuestiones relacionadas