Очистка шума из трассировки стека Java
Мои трассировки стека Java содержат много записей, которые мне не нужны, показывая вызов метода через прокси и методы отражения Spring и тому подобное. Это может сделать довольно сложным выделить часть трассировки стека, которая фактически из моего кода. Ruby on Rails включает в себя "очиститель трассировки стека", где вы можете указать список шаблонов трассировки стека, чтобы опустить из печатных трасс стека - какой лучший способ сделать что-то подобное, универсально, для Java?
Было бы лучше, если бы это работало повсюду, в том числе в бегуне Eclipse jUnit.
Ответы
Ответ 1
eclipse имеет предпочтение Шаблоны фильтра трассировки стека (посмотрите на java > junit или найдите stacktrace
в настройках). Вы можете игнорировать пакеты (также с подстановочными знаками), классы или методы. Работает для прямых тестовых вызовов (через Run как junit Test), а не для командной строки, например, ant
или maven
.
Ответ 2
intellij-idea позволяет настраивать свертывание трассировки стека, особенно полезно с динамическими языками.
![IntelliJ]()
(источник: jetbrains.com)
и Анализ внешних трассировок стека.
Я могу представить общий инструмент/фильтр, работающий на уровне каркаса (например, logback или log4j). Я не думаю, что есть какая-либо общая поддержка для этого, но я думаю, что это хорошая идея для реализации этого. Я посмотрю, может быть, это не так много работы.
ОБНОВЛЕНИЕ: я реализовал фильтрацию нерелевантных линий трассировки стека в журналах для logback, а также следую LBCLASSIC-325.
Ответ 3
Я на самом деле написал библиотеку с открытым исходным кодом MgntUtils (доступна на Github и maven central), которая содержит несколько утилит. Вот ссылка на статью о библиотеке: Java-библиотека с открытым исходным кодом MgntUtils. Одна из утилит - это универсальный фильтр стековой трассировки, который я широко использовал и нашел его очень полезным. Класс называется TextUtils и имеет метод getStacktrace() с несколькими переопределенными сигнатурами. Он принимает экземпляр Throwable и позволяет установить префикс пакета соответствующих пакетов. Допустим, ваша балансовая единица всегда находится в пакетах, начинающихся с "com.plain. *". Таким образом, вы устанавливаете такой префикс и делаете это
logger.info(TextUtils.getStacktrace(e, true, "com.plain."));
это очень аккуратно отфильтрует все ненужные части трассы, оставляя вам очень краткую трассировку стека. Кроме того, я нашел очень удобным предварительно установить префикс, а затем просто использовать метод удобства
TextUtils.getStacktrace(e);
Это будет делать то же самое. Для установки префикса просто используйте метод
setRelevantPackage("com.plain.");
Также, если вы используете среду Spring, вы можете добавить следующий сегмент в конфигурацию Spring, а затем все у вас будет настроено:
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="com.mgnt.utils.TextUtils"/>
<property name="targetMethod" value="setRelevantPackage"/>
<property name="arguments" value="com.plain."/>
</bean>
Библиотека поставляется с хорошо написанным (я надеюсь) Javadoc, который объясняет все подробно. Но вот небольшой тизер: вы получите следующую трассировку стека:
at com.plain.BookService.listBooks()
at com.plain.BookService$$FastClassByCGLIB$$e7645040.invoke()
at net.sf.cglib.proxy.MethodProxy.invoke()
...
at com.plain.LoggingAspect.logging()
at sun.reflect.NativeMethodAccessorImpl.invoke0()
...
at com.plain.BookService$$EnhancerByCGLIB$$7cb147e4.listBooks()
at com.plain.web.BookController.listBooks()
вместо
at com.plain.BookService.listBooks()
at com.plain.BookService$$FastClassByCGLIB$$e7645040.invoke()
at net.sf.cglib.proxy.MethodProxy.invoke()
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed()
at com.plain.LoggingAspect.logging()
at sun.reflect.NativeMethodAccessorImpl.invoke0()
at sun.reflect.NativeMethodAccessorImpl.invoke()
at sun.reflect.DelegatingMethodAccessorImpl.invoke()
at java.lang.reflect.Method.invoke()
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs()
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod()
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.aop.interceptor.AbstractTraceInterceptor.invoke()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept()
at com.plain.BookService$$EnhancerByCGLIB$$7cb147e4.listBooks()
at com.plain.web.BookController.listBooks()
Ответ 4
Для log4j:
package package1;
public class FilteringThrowableRenderer implements ThrowableRenderer {
private static final String PACKAGES_SEPARATOR = "\\s*,\\s*";
private final static String TRACE_PREFIX = "\tat ";
private static final String FILTERED_WARNING = " [Stacktrace is filtered]";
ThrowableRenderer defaultRenderer = new EnhancedThrowableRenderer();
List<String> skippedLinePrefixes;
public FilteringThrowableRenderer() {
String skippedPackagesString = "java,org"; // TODO: move it to config
String[] skippedPackages =
skippedPackagesString.trim().split(PACKAGES_SEPARATOR);
skippedLinePrefixes = new ArrayList<String>(skippedPackages.length);
for (String packageName : skippedPackages) {
skippedLinePrefixes.add(TRACE_PREFIX + packageName);
}
}
@Override
public String[] doRender(Throwable throwable) {
String[] initialTrace = defaultRenderer.doRender(throwable);
if (!skippedLinePrefixes.isEmpty()) {
List<String> result = new ArrayList<String>(initialTrace.length);
boolean filtered = false;
trace: for (String element : initialTrace) {
for (String skippedLinePrefix : skippedLinePrefixes) {
if (element.startsWith(skippedLinePrefix)) {
filtered = true;
continue trace;
}
}
result.add(element);
}
if (filtered && result.size() > 0) {
result.set(0, result.get(0) + FILTERED_WARNING);
}
return result.toArray(new String[result.size()]);
} else {
return initialTrace;
}
}
}
чтобы включить его с кодом:
ThrowableRendererSupport loggerRepository =
(ThrowableRendererSupport) LogManager.getLoggerRepository();
loggerRepository.setThrowableRenderer(new FilteringThrowableRenderer());
или с log4j.properties:
log4j.throwableRenderer=package1.FilteringThrowableRenderer
Ответ 5
Не совсем то, что вы ищете (и, насколько мне известно, универсального решения для вашей проблемы нет, по крайней мере, я никогда не слышал о знаменитом инструменте для очистки и извлечения информации из Java stacktraces).
В любом случае этот пост от 05 июля 2011 года в блоге Faux описывает Java-агент на ранних этапах, целью которого является обогащение ( а не фильтровать) трассировки стека. Он поддерживает ссылку на репозиторий git с проектом mavenized. Может быть, вы можете пойти отсюда, настроить его код и бросить свое собственное решение (кто знает, может даже начать проект с открытым исходным кодом).
Ответ 6
Этот плагин довольно приятный
https://marketplace.eclipse.org/content/grep-console
Просто обобщенная утилита форматирования grep для консоли Eclipse, поэтому никаких дополнительных зависимостей нет. Я отформатирую весь свой неулокальный шум на серый текст.