Como posso detectar quando uma exceção foi lançada globalmente em Java?

StackOverflow https://stackoverflow.com/questions/75218

  •  09-06-2019
  •  | 
  •  

Pergunta

Como posso detectar quando uma exceção foi lançada em qualquer lugar do meu aplicativo?

Tento enviar automaticamente um e-mail para mim mesmo sempre que uma exceção é lançada em qualquer lugar do meu aplicativo Java Desktop.Acho que assim posso ser mais proativo.

Eu sei que poderia simplesmente registrar-me explicitamente e me notificar sempre que ocorrer uma exceção, mas teria que fazer isso em qualquer lugar e poderia (mais provavelmente) perder algumas.

Alguma sugestão?

Foi útil?

Solução

Você provavelmente não deseja enviar nenhuma exceção.Existem muitos códigos no JDK que realmente dependem de exceções para funcionar normalmente.Presumo que você esteja mais interessado em exceções não detectadas.Se você estiver capturando as exceções, deverá tratar as notificações lá.

Em um aplicativo de desktop, há dois lugares para se preocupar com isso: no (EDT) e fora do EDT.Globalmente você pode registrar uma classe implementando java.util.Thread.UncaughtExceptionHandler e cadastre-se através java.util.Thread.setDefaultUncaughtExceptionHandler.Isso será chamado se uma exceção chegar ao final da pilha e o thread não tiver um manipulador definido na instância do thread atual no thread ou no ThreadGroup.

O EDT possui um gancho diferente para lidar com exceções.Uma propriedade do sistema 'sun.awt.exception.handler' precisa ser registrado com o nome de classe totalmente qualificado de uma classe com um construtor de argumento zero.Esta classe precisa de um método de instância handle(Throwable) que faz o seu trabalho.O tipo de retorno não importa e, como uma nova instância é criada toda vez, não conte com a manutenção do estado.

Portanto, se você não se importa com qual thread a exceção ocorreu em uma amostra, pode ficar assim:

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

Adicione esta classe em algum pacote aleatório e então chame o registerExceptionHandler método e você deve estar pronto para começar.

Outras dicas

Os novos ganchos de depuração no Java 1.5 permitem fazer isso.Permite, por ex."quebrar qualquer exceção" nos depuradores.

Aqui está o Javadoc específico você precisa.

Confira Thread.UncaughtExceptionHandler.Você pode configurá-lo por thread ou por padrão para toda a VM.

Isso pelo menos ajudaria você a pegar aqueles que você perdeu.

Se você estiver usando uma estrutura da web como Primavera então você pode delegar seu web.xml para uma página e usar o controlador para enviar o email.Por exemplo:

Em web.xml:

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

Em seguida, defina /error/500.htm como um controlador.Você pode acessar a exceção a partir do parâmetro javax.servlet.error.exception:

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

Se você está apenas executando um programa Java normal, imagino que você esteja preso a public static void main(String[] args) { try { ...} catch (Exceção e) {} }

Se você estiver usando java 1.3/1.4, Thread.UncaughtExceptionHandler não estará disponível.Neste caso você pode usar uma solução baseada em AOP para acionar algum código quando uma exceção for lançada.Spring e/ou AspectJ podem ser úteis.

No meu projeto atual enfrentei requisitos semelhantes em relação à detecção de erros.Para este propósito, apliquei a seguinte abordagem:Eu uso o log4j para fazer login em meu aplicativo e, em todos os lugares onde a exceção é detectada, faço o padrão: log.error("Error's description goes here", e);, onde e é a exceção que está sendo lançada (consulte a documentação do log4j para obter detalhes sobre a inicialização do "log").Para detectar o erro, utilizo meu próprio Appender, que estende a classe log4j 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;
        }
    }
}

O arquivo de configuração log4j deve conter apenas uma definição do novo anexador e seu anexo ao logger selecionado (root no meu caso):

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

Você pode chamar o método errosOccured() do ErrosDetectingAppender em algum ponto significativo no fluxo de execução de seus programas ou reagir imediatamente adicionando funcionalidade ao bloco if no método append().Esta abordagem é consistente com a semântica:coisas que você considera erros e as registra como tal são detectadas.Se mais tarde você considerar os erros selecionados não tão importantes, basta alterar o nível de registro para log.warn() e o relatório não será enviado.

Nesse caso, acho que sua melhor aposta seria escrever um carregador de classe personalizado para lidar com todo o carregamento de classe em seu aplicativo e, sempre que uma classe de exceção for solicitada, você retornará uma classe que agrupa a classe de exceção solicitada.Esse wrapper chama a exceção agrupada, mas também registra o evento de exceção.

Presumo que você não quer dizer qualquer Exceção, mas sim qualquer não capturado Exceção.

Se esse é o caso este artigo no site da Sun tem algumas ideias.Você precisa agrupar seu método de nível superior em um try-catch bloquear e também fazer algum trabalho extra para lidar com outros Threads.

O envio de um e-mail pode não ser possível se você estiver recebendo uma exceção de tempo de execução como OutOfMemoryError ou StackOverflow.Muito provavelmente você terá que gerar outro processo e capturar quaisquer exceções lançadas por ele (com as diversas técnicas mencionadas acima).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top