Мониторинг Java изнутри Java
-
06-07-2019 - |
Вопрос
Я хочу написать простую визуализацию Java-программы, отображая вызовы методов программы в виде ветвей дерева.Это можно было бы сделать довольно просто, попросив саму программу сообщить визуализации, что она делает, но я хочу иметь возможность делать это с любым методом / классом Java, а не только с теми, которые я изменяю для этого.
Что мне нужно, так это возможность отслеживать методы, которые вызывает программа, и какие методы вызываются внутри этого метода, и так далее.Очевидно, что трассировки стека обеспечивают именно эту функциональность:
java.lang.NullPointerException
at MyClass.mash(MyClass.java:9)
at MyClass.crunch(MyClass.java:6)
at MyClass.main(MyClass.java:3)
Поэтому я подумал о том, чтобы запустить программу, которую я хочу отслеживать, в потоке, а затем просто посмотреть на стек этого потока.Однако класс thread на самом деле не поддерживает это.Он только поддерживает печать текущий стек.
Теперь я, конечно, подумал о том, чтобы просто изменить поток печати системного класса, чтобы поток печатал свой стек в мой PrintStream, но это кажется каким-то неправильным.
Есть ли лучший способ сделать это?Есть ли какие-либо уже существующие классы / методы, которые я могу использовать?
Кроме того, в настоящее время я загружаю исходный код Java, чтобы проверить, как именно класс thread печатает свой стек, поэтому я мог бы, возможно, создать подкласс thread и имитировать метод dumpStack() своим собственным методом getStack().
Решение 2
Ой, просматривая исходный код, я заметил, что у класса потока есть метод public StackTraceElement [] getStackTrace (), его просто нет в документации, которую я читал. Теперь я чувствую себя глупо.
Так что да, похоже, это решение.
Другие советы
Посмотрите также на VisualVM, поставляемый с последними выпусками Java.
Одним из подходов может быть использование чего-то вроде BCEL для предварительной обработки целевого байт-кода для вставки вызовов в ваш собственный код при каждом входе и выходе метода (вероятно, лучше всего выполнить выход, обернув весь метод в блок try / finally, чтобы перехватить исключения при выходе). Отсюда вы можете вывести дерево вызовов именно так, как оно происходит.
Взгляните на ThreadMXBean ( многопоточный ) класс - это то, что вам нужно.По сути, вы:
- вызовите ManagementFactory.getThreadMXBean(), чтобы получить экземпляр ThreadMXBean;
- вызовите getAllThreadIds() в результирующем ThreadMXBean для перечисления текущих потоков;
- вызовите getThreadInfo(), чтобы получить n верхних элементов трассировки стека из заданного списка потоков.