Как я могу определить, когда Исключение было создано глобально в Java? - PullRequest
26 голосов
/ 16 сентября 2008

Как я могу определить, когда в моем приложении появилось исключение?

Я пытаюсь автоматически отправлять себе электронное письмо всякий раз, когда в моем настольном приложении Java выдается исключение. Я полагаю, что таким образом я могу быть более активным.

Я знаю, что мог бы просто явно регистрироваться и уведомлять себя всякий раз, когда происходит исключение, но я должен был бы делать это везде, и я мог бы (более вероятно, пропустить) пару.

Есть предложения?

Ответы [ 9 ]

37 голосов
/ 16 сентября 2008

Вы, вероятно, не хотите отправлять письма по любому исключению. В JDK много кода, который в действительности зависит от исключений для нормальной работы. Я полагаю, что вас больше не интересуют неисследованные исключения. Если вы ловите исключения, вы должны обрабатывать уведомления там.

В настольном приложении можно беспокоиться об этом в двух местах: в потоке событий (EDT) и вне EDT. Глобально вы можете зарегистрировать класс, реализующий java.util.Thread.UncaughtExceptionHandler, и зарегистрировать его через java.util.Thread.setDefaultUncaughtExceptionHandler. Это будет вызвано, если исключение сворачивается в конец стека, и поток не имеет обработчика, установленного в текущем экземпляре потока в потоке или в ThreadGroup.

EDT имеет другой хук для обработки исключений. Системное свойство 'sun.awt.exception.handler' должно быть зарегистрировано с полным именем класса для класса с конструктором с нулевым аргументом. Этот класс нуждается в дескрипторе метода экземпляра (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, и вы должны быть готовы к работе.

5 голосов
/ 16 сентября 2008

Новые возможности отладки в Java 1.5 позволяют вам это делать. Это позволяет, например, «разбить на любое исключение» в отладчиках.

Вот конкретный Javadoc , который вам нужен.

4 голосов
/ 16 сентября 2008

Извлечь Thread.UncaughtExceptionHandler . Вы можете установить его для каждого потока или по умолчанию для всей виртуальной машины.

Это, по крайней мере, поможет вам поймать тех, кого вы пропустили.

1 голос
/ 16 ноября 2011

В моем текущем проекте я столкнулся с аналогичным требованием в отношении обнаружения ошибок. Для этой цели я применил следующий подход: я использую log4j для регистрации в своем приложении, и везде, где перехватывается исключение, я делаю стандартную вещь: log.error("Error's description goes here", e);, где e - исключение (подробности см. В документации log4j). по поводу инициализации "лога"). Чтобы обнаружить ошибку, я использую свой собственный Appender, который расширяет класс 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;
        }
    }
}

Файл конфигурации log4j должен просто содержать определение нового приложения и его присоединение к выбранному регистратору (в моем случае, root):

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

Вы можете либо вызвать метод errorsOccured () в ErrorsDetectingAppender в какой-то важный момент в потоке выполнения ваших программ, либо немедленно отреагировать, добавив функциональность в блок if в методе append (). Этот подход согласуется с семантикой: вещи, которые вы считаете ошибочными и регистрируете их как таковые, обнаруживаются. Если позднее вы посчитаете выбранные ошибки не столь важными, просто измените уровень ведения журнала на log.warn (), и отчет не будет отправлен.

1 голос
/ 17 сентября 2008

Если вы используете Java 1.3 / 1.4, Thread.UncaughtExceptionHandler недоступен. В этом случае вы можете использовать решение на основе AOP для запуска некоторого кода при возникновении исключения. Весна и / или аспект J могут быть полезны.

1 голос
/ 16 сентября 2008

Если вы используете веб-фреймворк, такой как Spring , вы можете делегировать в своем файле 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-программу, то я думаю, что вы застряли с публичной статической void main (String [] args) {try {...} catch (Exception e) {}}

0 голосов
/ 16 сентября 2008

Отправка электронного письма может быть невозможна, если вы получаете исключение во время выполнения, например OutOfMemoryError или StackOverflow. Скорее всего, вам придется порождать другой процесс и перехватывать любые исключения, вызванные им (с помощью различных методов, упомянутых выше).

0 голосов
/ 16 сентября 2008

Полагаю, вы не имеете в виду любое исключение, а скорее любое необнаруженное исключение.

Если это так В этой статье на веб-сайте Sun есть несколько идей. Вам нужно обернуть ваш метод верхнего уровня в блок try-catch, а также проделать дополнительную работу для обработки других потоков.

0 голосов
/ 16 сентября 2008

В этом случае я думаю, что вам лучше всего написать собственный загрузчик классов для обработки всей загрузки классов в вашем приложении, и всякий раз, когда запрашивается класс исключений, вы возвращаете класс, который упаковывает запрошенный класс исключений. Эта обертка вызывает обернутое исключение, но также регистрирует событие исключения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...