Что такое стектрейс java
Перейти к содержимому

Что такое стектрейс java

  • автор:

Необычная Java: StackTrace Extends Throwable

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

Chronicle Software обычно использует ряд различных шаблонов в своих низкоуровневых библиотеках, с которыми большинство разработчиков вообще не сталкивается.

Один из них — это класс, который расширяет Throwable, но не является ошибкой или исключением.

StackTrace Extends Throwable

package net.openhft.chronicle.core; /** * Throwable created purely for the purposes of reporting a stack trace. * This is not an Error or an Exception and is not expected to be thrown or caught. */ public class StackTrace extends Throwable < public StackTrace() < this("stack trace"); >public StackTrace(String message) < this(message, null); >public StackTrace(String message, Throwable cause) < super(message + " on " + Thread.currentThread().getName(), cause); >public static StackTrace forThread(Thread t) < if (t == null) return null; StackTrace st = new StackTrace(t.toString()); StackTraceElement[] stackTrace = t.getStackTrace(); int start = 0; if (stackTrace.length >2) < if (stackTrace[0].isNativeMethod()) < start++; >> if (start > 0) < StackTraceElement[] ste2 = new StackTraceElement[stackTrace.length - start]; System.arraycopy(stackTrace, start, ste2, 0, ste2.length); stackTrace = ste2; >st.setStackTrace(stackTrace); return st; > >

Некоторые важные примечания, чтобы для начала:

  • Это не тот класс исключения, которое, как я рассчитываю, когда-либо может возникнуть. Классы, непосредственно расширяющие Throwable, проверяются, как и Exception, поэтому компилятор поможет вам обеспечить эту проверку.
  • Трассировка стека Throwable определяется при создании Throwable, а не там, где она возникает. Обычно это одна и та же строка, но это не обязательно. Чтобы получить трассировку стека, Throwable не должно вызвать исключение.
  • Объекты элементов трассировки стека не создаются до тех пор, пока они не потребуются. Вместо этого метаданные добавляются к самому объекту, чтобы уменьшить накладные расходы, а массив StackTraceElements заполняется при первом использовании.

Однако давайте рассмотрим этот класс более подробно. Класс будет протоколировать как трассировку стека, где он был создан, так и поток, который его создал. Позже вы увидите насколько это полезно.

Этот класс также можно использовать для хранения трассировки стека другого запущенного потока.

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

Связано это с тем, что JVM останавливает поток, и обычно JVM ждут, чтобы остановить каждый поток, поэтому он может проверить стек потока, который вы пытаетесь захватить. Т.е. это имеет высокие накладные расходы, но может быть очень полезным.

StackTrace как отложенное исключение

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

Почему был закрыт ресурс

public class EgMain < static class MyCloseable implements Closeable < protected transient volatile StackTrace closedHere; @Override public void close() < closedHere = new StackTrace("Closed here"); // line 13 >public void useThis() < if (closedHere != null) throw new IllegalStateException("Closed", closedHere); >> public static void main(String[] args) throws InterruptedException < MyCloseable mc = new MyCloseable(); // line 27 Thread t = new Thread(mc::close, "closer"); t.start(); t.join(); mc.useThis(); >>

При запуске код выдает следующее исключение:

Обычно вы увидите исключение IllegalStateException и место, где ваш код пытался использовать закрытый ресурс, но это не говорит вам, почему он был закрыт без дополнительной информации.

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

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

Какой ресурс был закрыт?

Долгоживущие объекты Closeable могут иметь сложный жизненный цикл, и обеспечение их закрытия, когда это необходимо, может быть трудно отследить. Что может привести к утечке ресурсов.

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

public class CreatedMain < static class MyResource implements Closeable < private final transient StackTrace createdHere = new StackTrace("Created here"); volatile transient boolean closed; @Override public void close() throws IOException < closed = true; >@Override protected void finalize() throws Throwable < super.finalize(); if (!closed) Logger.getAnonymousLogger().log(Level.WARNING, "Resource discarded but not closed", createdHere); >> public static void main(String[] args) throws InterruptedException < new MyResource(); // line 27 System.gc(); Thread.sleep(1000); >>

Код выводит следующее:

Что позволяет вам не только видеть, где был создан ресурс, что дает возможность определить, почему он не был закрыт, но и просто вести лог так, как понимает ваша IDE. Это возможно потому, что ваш объект Logger будет поддерживать выдачу трассировки стека. например, вы можете кликнуть по номеру строки, чтобы просмотреть код, создавший ее.

Мониторинг производительности критического потока в рабочей среде

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

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

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

public class JitteryMain implements Runnable < volatile long loopStartMS = Long.MIN_VALUE; volatile boolean running = true; @Override public void run() < while (running) < loopStartMS = System.currentTimeMillis(); doWork(); loopStartMS = Long.MIN_VALUE; >> private void doWork() < int loops = new Random().nextInt(100); for (int i = 0; i < loops; i++) pause(1); // line 24 >static void pause(int ms) < try < Thread.sleep(ms); // line 29 >catch (InterruptedException e) < throw new AssertionError(e); // shouldn't happen >> public static void main(String[] args) < final JitteryMain jittery = new JitteryMain(); Thread thread = new Thread(jittery, "jitter"); thread.setDaemon(true); thread.start(); // monitor loop long endMS = System.currentTimeMillis() + 1_000; while (endMS >System.currentTimeMillis()) < long busyMS = System.currentTimeMillis() - jittery.loopStartMS; if (busyMS >100) < Logger.getAnonymousLogger() .log(Level.INFO, "Thread spent longer than expected here, was " + busyMS + " ms.", StackTrace.forThread(thread)); >pause(50); > jittery.running = false; > >

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

Вам может быть интересно, почему это происходит в данном случае. Наиболее вероятная причина заключается в том, что Thread.sleep(time) спит в течение минимального, а не максимального времени, а в Windows спящий режим 1 мс на самом деле довольно стабильно занимает около 1,9 мс.

Обнаружение одновременного доступа к однопоточному ресурсу разными потоками

package net.openhft.chronicle.core; public class ConcurrentUsageMain < static class SingleThreadedResource < private StackTrace usedHere; private Thread usedByThread; public void use() < checkMultithreadedAccess(); // BLAH >private void checkMultithreadedAccess() < if (usedHere == null || usedByThread == null) < usedHere = new StackTrace("First used here"); usedByThread = Thread.currentThread(); >else if (Thread.currentThread() != usedByThread) < throw new IllegalStateException("Used two threads " + Thread.currentThread() + " and " + usedByThread, usedHere); >> > public static void main(String[] args) throws InterruptedException < SingleThreadedResource str = new SingleThreadedResource(); final Thread thread = new Thread(() ->str.use(), "Resource user"); // line 25 thread.start(); thread.join(); str.use(); // line 29 > >

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

Отключение этой трассировки

Создание StackTrace оказывает значительное влияние на поток и, возможно, на JVM. Однако его легко отключить с помощью управляющего флага, такого как системное свойство, и заменить его нулевым значением.

createdHere = Jvm.isResourceTracing() ? new StackTrace(getClass().getName() + " created here") : null;

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

Заключение

Хотя класс, который напрямую расширяет Throwable, выглядит странно, он разрешен.

Более того он удивительно полезен для предоставления дополнительной информации о жизненном цикле ресурса или добавления простого мониторинга, который вы можете запустить в рабочей среде.

Stack trace

Получение стек-трейса

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

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

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

Стек-трейс

Например, в любой момент работы программы можно узнать класс и имя метода, который сейчас выполняется. И даже не одного метода, а получить информацию о всей цепочке вызовов методов от текущего метода до метода main() .

Список, состоящий из текущего метода, метода, который его вызвал, его вызвавшего метода и т.д., называется stack trace . Получить его можно с помощью команды:

StackTraceElement[] methods = Thread.currentThread().getStackTrace();

Можно записать ее и в две строки:

Thread current = Thread.currentThread(); StackTraceElement[] methods = current.getStackTrace();

Статический метод currentThread() класса Thread возвращает ссылку на объект типа Thread , который содержит информацию о текущей нити (о текущем потоке выполнения). Подробнее о нитях вы узнаете в квесте Java Core .

У этого объекта Thread есть метод getStackTrace() , который возвращает массив элементов StackTraceElement , каждый из которых содержит информацию об одном методе. Все элементы вместе и образуют stack trace .

public class Main < public static void main(String[] args) < test(); > public static void test() < Thread current = Thread.currentThread(); StackTraceElement[] methods = current.getStackTrace(); for(var info: methods) System.out.println(info); > >
java.base/java.lang.Thread.getStackTrace(Thread.java:1606) Main.test(Main.java:11) Main.main(Main.java:5) 

Как мы видим по выводу на экран, в приведенном примере метод getStackTrace() вернул массив из трех элементов:

  • Метод getStackTrace () класса Thread
  • Метод test () класса Main
  • Метод main () класса Main

Из этого стек-трейса можно сделать вывод, что:

  • Метод Thread.getStackTrace() был вызван методом Main.test() в строке 11 файла Main.java
  • Метод Main.test() был вызван методом Main.main() в строке 5 файла Main.java
  • Метод Main.main() никто не вызывал — это первый метод в цепочке вызовов.

Кстати, на экране отобразилась только часть всей имеющийся информации. Все остальное можно получить прямо из объекта StackTraceElement

2. StackTraceElement

Класс StackTraceElement , как следует из его названия, создан для того, чтобы хранить информацию по одному элементу stack trace — т.е. по одному методу из StackTrace .

У объектов этого класса есть такие методы:

String getClassName()
String getMethodName()
String getFileName()
int getLineNumber()
String getModuleName()
String getModuleVersion()

С их помощью можно получить более полную информацию о текущем стеке вызовов:

public class Main < public static void main(String[] args) < test(); > public static void test() < Thread current = Thread.currentThread(); StackTraceElement[] methods = current.getStackTrace(); for(StackTraceElement info: methods) < System.out.println(info.getClassName()); System.out.println(info.getMethodName()); System.out.println(info.getFileName()); System.out.println(info.getLineNumber()); System.out.println(info.getModuleName()); System.out.println(info.getModuleVersion()); System.out.println(); > > >
java.lang.Thread getStackTrace Thread.java 1606 java.base 11.0.2 Main test Main.java 11 null null Main main Main.java 5 null null

имя класса
имя метода
имя файла
номер строки
имя модуля
версия модуля

3. Стек

Что такое Stack Trace вы уже знаете, а что же такое сам Stack (Стек)?

Стек — это структура хранения данных, в которую можно добавлять элементы и из которой можно забирать элементы. Причем брать элементы можно только с конца: сначала последний добавленный, потом — предпоследний, и т.д.

Само название Stack переводится с английского как «стопка» и очень похоже на стопку бумаги. Если вы положите на стопку бумаги листы 1, 2 и 3, взять вы их сможете только в обратном порядке: сначала третий, затем второй, а только затем первый.

В Java даже есть специальная коллекция с таким поведением и таким же названием — Stack. Этот класс в своем поведении очень похож на ArrayList и LinkedList . Однако у него есть еще методы, которые реализуют поведение стека:

T push(T obj)
T pop()
T peek()
boolean empty()
int search(Object obj)
StackInteger> stack = new StackInteger>(): stack.push(1); stack.push(2); stack.push(3); int x = stack.pop(); stack.push(4); int y = stack.peek(); stack.pop(); stack.pop();
 [1] [1, 2] [1, 2, 3] [1, 2] [1, 2, 4] [1, 2, 4] [1, 2] [1] 

Стек используется в программировании довольно часто. Так что это полезная коллекция.

4. Вывод стек-трейса при обработке ошибок

Почему же список вызовов методов назвали StackTrace ? Да потому, что если представить список методов в виде стопки листов с именами методов, при вызове очередного метода на эту стопку кладется лист с именем метода, на него — следующий, и т.д.

Когда метод завершается, лист с верха стопки удаляется. Нельзя удалить лист из середины стопки, не удалив все листы, лежащие в нем — нельзя прекратить работу метода в цепочке вызовов, не завершив все методы, вызванные им.

Исключения

Еще одно интересное применение стека — обработка исключений.

Когда в программе происходит ошибка и создается исключение , в него записывается текущий stack trace : массив, состоящий из списка методов начиная с метода main и заканчивая методом, где произошла ошибка. Там даже есть строка, в которой было создано исключение!

Этот stack trace ошибки хранится внутри исключения и может быть легко извлечен из нее с помощью метода: StackTraceElement[] getStackTrace ()

try < // тут может возникнуть исключение >catch(Exception e) < StackTraceElement[] methods = e.getStackTrace() >

Это метод класса Throwable , а значит, все его классы-наследники (т.е. вообще все исключения), имеют метод getStackTrace() . Очень удобно, не так ли?

Печать стек-трейса ошибки

Кстати, у класса Throwable есть еще один метод для работы со stack-trace: он выводит в консоль всю информацию по stack trace, который хранится внутри исключения. Он так и называется printStackTrace() .

Вызвать его можно у любого исключения, что очень удобно.

try < // тут может возникнуть исключение >catch(Exception e) < e.printStackTrace(); >
java.base/java.lang.Thread.getStackTrace(Thread.java:1606) Main.test(Main.java:11) Main.main(Main.java:5)

Комментарии (185)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Егор Уровень 26 Expert
3 февраля 2024

 Stack stack = new Stack<>(); stack.push("Понедельник"); stack.push("Вторник"); stack.push("Среда"); stack.push("Четверг"); System.out.println(stack.search("Понедельник")); // выводит элемент 4 System.out.println(stack.get(0)); // выводит понедельник System.out.println(stack.search("Четверг")); // выводит элемент 1 System.out.println(stack.get(3)); // выводит четверг 

Получается, что метод search() выводит нам не индекс, как написано в лекции, а именно порядковый (человеческий) номер, а уже indexOf() у стэка выведет индекс. Причём индекс идёт в обратном порядке к нумерации

Кирилл Уровень 18
26 января 2024

Немного эмоций после решения задачки на Стэк�� === Мы рассказали вам о том, какая это интересная вещь — Stack, и как она работает. Вот видите, каждый новый элемент добавляется в конец списка, как листок или поднос наверх стопки. И забираем мы элементы в обратном порядке, сначала последний, потом следующий и так, пока не останется ни одного. Все понятно? Замечательно. А теперь давайте напишем программу, которая имитирует работу Стэка. Готовы? Начали. «Стек в домашних условиях». Не получается? А ну просто мы решили изменить логику, и в программе поставили условия, что элементы надо добавлять и забирать из начала списка. Ну то есть, как-будто вы подходите к стопке бумаги, аккуратно приподнимаете ее и достаете самый нижний листок. Потом аккуратно кладете все на место. Не благодарите! Зачем мы так сделали? Хммм. это. секунду. ща. <шепотом>— Серёг, а нахера мы так сделали то?? — . . Кхм. А это чтобы вы внимательно читали условия. Вот! === Когда с первого раза у меня решение не приняли, я сразу полез в готовый вариант, с мыслями, а неужто текст задачи не перепутан, и они реально этого хотели. Оказалось так)

Private Joker Уровень 18
25 января 2024

Тема конечно не самая простая, особенно Thread current = Thread.currentThread(); По задаче «стек в домашних условиях» не придумывайте велосипедов(циклов\if\else), а просто используйте методы коллекции по одной штуке, на каждую функцию.

Anastasia Frisman Уровень 16 Expert
12 января 2024

Да уж, да уж) В задаче «Стек в домашних условиях» не надо использовать методы стека. Вспоминаем аналогичные методы списка (LinkedList). Видимо, суть задачи в том, чтобы сравнить методы этих классов.

JIexa Уровень 16
3 января 2024

Задача: Лонг дринк чтоб получить стек вызовов нужно в методе который падает добавить конструкцию try catch и в catch вызвать стек. это можно сделать двумя способами: 1.

 Thread current = Thread.currentThread(); StackTraceElement[] methods = current.getStackTrace(); for(var info: methods)

Thread current = Thread.currentThread();: Создается объект типа Thread, представляющий текущий поток выполнения программы. Этот объект присваивается переменной current. StackTraceElement[] methods = current.getStackTrace();: Вызывается метод getStackTrace() для объекта текущего потока, возвращая массив объектов StackTraceElement. Эти объекты содержат информацию о стеке вызовов текущего потока, включая информацию о классах, методах, файлах и номерах строк вызовов. далее полученный массив выводим в консоль циклом (стек в массиве) 2. или как нужно по заданию, две строки кода: Thread current = Thread.currentThread(); StackTraceElement[] methods = current.getStackTrace(); это тоже самое что и эта строка (упростили): StackTraceElement[] methods = Thread.currentThread().getStackTrace(); Значит надо эту часть: «Thread.currentThread().getStackTrace();» вызвать в методе printBugMethodName() и сам метод printBugMethodName переписать так, чтоб он печатал не одну ячейку массива а все ячейки

Что такое stacktrace?

Всем привет
Гуру программирования, подскажите плз:
Насколько корректно говорит stacktrace о выхлопе питоновского скрипта (errors). Нашел определение на вики, там говорится что stacktrace это вывод переменных кучи\стэка в момент исполнения. Моих «школярских» познаний в программровании хватает на то, чтобы вспомнить что стэк\куча — сущности употребляемые в объектных языках, а питон интерпретируемый. Отсюда вопрос — насколько корректно говорить про stacktrace если говорить и логировании ошибок в питоне
Спасибо

  • Вопрос задан более трёх лет назад
  • 11176 просмотров

Комментировать
Решения вопроса 1

leahch

3Д специалист. Долго, Дорого, Дерьмово.

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

Ответ написан более трёх лет назад
Комментировать
Нравится 4 Комментировать
Ответы на вопрос 1

«Объектные» языки и интерпретируемые это тоже самое, что тёплое и мягкое.
Язык может быть объектно-ориентированным и в тоже время интерпретируемым. А может быть процедурным, но компилируемым. Это не взаимоисключающие свойства.

А стек и куча — да они в любом языке есть. Даже если к ним нет прямого доступа. Механизм вызова функций и возврата из них основан на стеке, это реализовано на аппаратном уровне.

Что такое stack trace, и как с его помощью находить ошибки при разработке приложений?

Мне сказали, что это называется «трассировкой стека» или «stack trace». Что такое трассировка? Какую полезную информацию об ошибке в разрабатываемой программе она содержит? Немного по существу: довольно часто я вижу вопросы, в которых начинающие разработчики, получая ошибку, просто берут трассировки стека и какой-либо случайный фрагмент кода без понимания, что собой представляет трассировка и как с ней работать. Данный вопрос предназначен специально для начинающих разработчиков, которым может понадобиться помощь в понимании ценности трассировки стека вызовов. Перевод вопроса: «What is a stack trace, and how can I use it to debug my application errors?» @Rob Hruska

Отслеживать
123k 24 24 золотых знака 128 128 серебряных знаков 307 307 бронзовых знаков
задан 7 апр 2016 в 10:45
Nicolas Chabanovsky Nicolas Chabanovsky
51.4k 87 87 золотых знаков 267 267 серебряных знаков 505 505 бронзовых знаков
ассоциация: stackoverflow.com/questions/3988788
24 фев 2017 в 9:10

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Простыми словами, трассировка стека – это список методов, которые были вызваны до момента, когда в приложении произошло исключение.

Простой случай

В указанном примере мы можем точно определить, когда именно произошло исключение. Рассмотрим трассировку стека:

Exception in thread "main" java.lang.NullPointerException at com.example.myproject.Book.getTitle(Book.java:16) at com.example.myproject.Author.getBookTitles(Author.java:25) at com.example.myproject.Bootstrap.main(Bootstrap.java:14) 

Это пример очень простой трассировки. Если пойти по списку строк вида «at…» с самого начала, мы можем понять, где произошла ошибка. Мы смотрим на верхний вызов функции. В нашем случае, это:

at com.example.myproject.Book.getTitle(Book.java:16) 

Для отладки этого фрагмента открываем Book.java и смотрим, что находится на строке 16 :

public String getTitle()

Это означает то, что в приведенном фрагменте кода какая-то переменная (вероятно, title ) имеет значение null .

Пример цепочки исключений

Иногда приложения перехватывают исключение и выбрасывают его в виде другого исключения. Обычно это выглядит так:

try < . >catch (NullPointerException e)

Трассировка в этом случае может иметь следующий вид:

Exception in thread "main" java.lang.IllegalStateException: A book has a null property at com.example.myproject.Author.getBookIds(Author.java:38) at com.example.myproject.Bootstrap.main(Bootstrap.java:14) Caused by: java.lang.NullPointerException at com.example.myproject.Book.getId(Book.java:22) at com.example.myproject.Author.getBookIds(Author.java:35) . 1 more 

В этом случае разница состоит в атрибуте «Caused by» («Чем вызвано»). Иногда исключения могут иметь несколько секций «Caused by». Обычно необходимо найти исходную причину, которой оказывается в самой последней (нижней) секции «Caused by» трассировки. В нашем случае, это:

Caused by: java.lang.NullPointerException  

Аналогично, при подобном исключении необходимо обратиться к строке 22 книги Book.java , чтобы узнать, что вызвало данное исключение – NullPointerException .

Еще один пугающий пример с библиотечным кодом

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

javax.servlet.ServletException: Произошло что–то ужасное at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.java:28) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.java:33) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388) at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216) at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182) at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765) at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418) at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) at org.mortbay.jetty.Server.handle(Server.java:326) at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542) at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943) at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756) at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218) at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404) at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228) at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582) Caused by: com.example.myproject.MyProjectServletException at com.example.myproject.MyServlet.doPost(MyServlet.java:169) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166) at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:30) . 27 more Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.example.myproject.MyEntity] at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:64) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2822) at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71) at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268) at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321) at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204) at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210) at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195) at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705) at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693) at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689) at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344) at $Proxy19.save(Unknown Source) at com.example.myproject.MyEntityService.save(MyEntityService.java:59)  

В этом примере приведен далеко не полный стек вызовов. Что вызывает здесь наибольший интерес, так это поиск функций из нашего кода – из пакета com.example.myproject . В предыдущем примере мы сначала хотели отыскать «первопричину», а именно:

Caused by: java.sql.SQLException 

Однако все вызовы методов в данном случае относятся к библиотечному коду. Поэтому мы перейдем к предыдущей секции «Caused by» и найдем первый вызов метода из нашего кода, а именно:

at com.example.myproject.MyEntityService.save(MyEntityService.java:59) 

Аналогично предыдущим примерам, необходимо обратить внимание на MyEntityService.java , строка 59 : именно здесь появилась ошибка (в данном случае ситуация довольно очевидная, так как об ошибке сообщает SQLException , но в этом вопросе мы рассматриваем именно процедуру отладки с помощью трассировки).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *