Рубрики
Без рубрики

Понимание трассировки стека в Java

Автор приглашенный автор Торбен Janssen Трассировка стека – одна из ключевых концепций Java. Это стек вызовов… Помеченный трассировками стека, java.

Автор приглашенный автор Торбен Janssen

Трассировка стека является одним из ключевых понятий в Java. Это стек вызовов для потока, в котором перечислены все вызовы методов с момента начала потока. Вы, вероятно, видели его текстовое представление в файле журнала или выводе консоли. Он печатается в System.out всякий раз, когда возникает исключение, которое не обрабатывается вашим приложением. Следующий фрагмент показывает типичный пример такого вывода.

java.lang.NumberFormatException: For input string: "123a45"
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)
    at java.base/java.lang.Long.parseLong(Long.java:699)
    at java.base/java.lang.Long.valueOf(Long.java:1151)
    at org.thoughts.on.java.TestStackTrace.testStackTrace(TestStackTrace.java:17)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    ...

Используя инструменты мониторинга, такие как Fusion Reactor, или вызывая метод getStackTrace() в текущем потоке, вы можете получить доступ к Stacktrace для всех активных потоков в вашей виртуальной машине. Но есть и другие способы изучения трассировки стека и работы с ней.

В большинстве случаев вы не будете просматривать Трассировку стека до тех пор, пока вам не понадобится проанализировать Исключение . StackTrace является частью объекта Exception и показывает все вызовы методов, которые происходили до тех пор, пока не было создано исключение. Это показывает вам, где произошло исключение и как вы достигли этой конкретной части кода.

На следующем шаге вы можете проанализировать свой код и выяснить, что вызвало исключение. Но это тема для другой статьи. В этом я хочу рассказать вам больше об исключениях с их Трассировкой стека s и вся информация, которую они предоставляют, чтобы вы лучше понимали трассировки стека в Java.

Исключения в Java

Исключение возникает всякий раз, когда в приложении Java возникает ошибка. Он будет представлен объектом java.lang. Исключение класс или один из его подклассов. JDK предоставляет вам огромный набор различных Исключение классы. Если вы хотите, вы также можете реализовать свои собственные бизнес-исключения.

Обычно рекомендуется использовать наиболее конкретный класс исключений для каждой ошибки. Типичным примером этого является valueOf |/метод java.lang. Длинный класс. Вы можете вызвать его с помощью java.lang. Строка и он выдает java.lang. Исключение NumberFormatException если строка имеет формат , который нельзя разобрать на Длинный . Исключение NumberFormatException является подклассом исключения IllegalArgumentException , которое указывает, что методу было передано недопустимое значение аргумента. Как вы можете видеть, исключение IllegalArgumentException описывало бы ситуацию с ошибкой, но исключение NumberFormatException является более конкретным и должно быть предпочтительным.

private Long parseToLong(String s) {
    return Long.valueOf(s);
}

Long l;
try {
    l = parseToLong(s);
} catch (NullPointerException npe) {
    // handle NullPointerException
    log.error("No value provided. Using 0 as default.", npe);
    l = 0L;
}
log.info(l);

Использование наиболее специфичного класса исключений облегчает чтение кода и позволяет реализовать другое предложение catch для каждого класса исключений. Это позволяет вам обрабатывать каждую ситуацию с ошибкой по-разному.

Вы могли бы, например, решить создать исключение NullPointerException если предоставленная строка равна нулю и выдает Исключение NumberFormatException если оно не имеет правильного формата.

private Long parseToLong(String s) {
    if (s == null) {
        throw new NullPointerException("String can't be null");
    }
    return Long.valueOf(s);
}

В коде, вызывающем этот метод, вы можете реализовать 2 отдельных блока catch , которые обрабатывают исключение NullPointerException и исключение Numberformatexception

Long l;
try {
    l = parseToLong(s);
} catch (NullPointerException npe) {
    // handle NullPointerException
    log.error("No value provided. Using 0 as default.", npe);
    l = 0L;
} catch (NumberFormatException nfe) {
    // handle NullPointerException
    log.error("Provided value was invalid. Using 0 as default.", nfe);
    l = 0L;
}
log.info(l);

Структура трассировки стека

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

15:28:34,694  ERROR TestStackTrace:26 - Provided value was invalid. Using 0 as default.
java.lang.NumberFormatException: For input string: "123a45"
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)
    at java.base/java.lang.Long.parseLong(Long.java:699)
    at java.base/java.lang.Long.valueOf(Long.java:1151)
    at org.thoughts.on.java.TestStackTrace.parseToLong(TestStackTrace.java:39)
TestStackTrace.java:39
    at org.thoughts.on.java.TestStackTrace.testStackTrace(TestStackTrace.java:18)
TestStackTrace.java:18
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)

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

Использование трассировок стека для анализа инцидентов

Если вы еще раз взглянете на ранее показанный StackTrace , вы увидите, что исключение было создано в Forinputstring метод исключения NumberFormatException класса. Фактическая проблема возникла в методе parseLong класса Long , который был вызван методом valueOf того же класса, который был вызван методом parsetolong моего класса TestStackTrace . Как вы можете видеть, трассировка стека, предоставляемая NumberFormatException , четко показывает, где произошло исключение и какая цепочка вызовов методов приводит к нему.

Эта информация является хорошим началом для анализа исключения и поиска его действительной причины. Но довольно часто вам потребуется больше информации, чтобы понять проблему. Объект Исключение и его Трассировка стека описывают только то, какая ошибка произошла и где она произошла. Но они не предоставляют вам никакой дополнительной информации, например, значений определенных переменных. Это может очень затруднить воспроизведение ошибки в тестовом примере.

Как FusionReactor может помочь

Термоядерный реактор может предоставить вам дополнительную информацию о ситуации с ошибкой. Если вы хотите, вы даже можете отладить проблемы в вашей операционной системе, когда это произойдет в следующий раз.

Единственное, что вам нужно сделать, это войти в веб-интерфейс экземпляра FusionReactor, который отслеживает ваше приложение, выбрать исключение из “Истории ошибок” и перейти на вкладку “Сведения об ошибке”. Там вы можете активировать отладчик для этого конкретного исключения.

После того, как вы это сделаете, Fusion Reactor отправит вам электронное письмо при повторном возникновении исключения и приостановит поток на заданный промежуток времени. Электронное письмо содержит трассировку стека и информацию о контексте переменной. Пока поток приостановлен, вы также можете использовать Производственный отладчик FusionReactor для отладки ошибки аналогичным образом, как в вашей среде разработки, не затрагивая другие потоки вашего приложения.

Оригинал: “https://dev.to/fusion_reactor/understanding-stacktraces-in-java-2pli”