2014-02-11 6 views
3

У меня есть метод Factory, который возвращает объект из ID-вызова.Извлечь только первые N строк трассировки стека

Пробный код:

public static Object getById(String id) { 
    Object o = CRUD.doRecovery(Class, id); 
    if(o == null) { 
     printLogMessage("recovery by ID returned Null: " + id); 
     // would really like to show only a few lines of stack trace. 
    } 
    return o; 
} 

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

+0

Пожалуйста, не используйте трассировки стека, чтобы узнать вызывающего метода. Это очень дорого (сравните [этот вопрос] (http://stackoverflow.com/questions/299068/how-slow-are-java-exceptions), который также имеет некоторые профилирующие данные.). Скорее используйте второй параметр и потребуйте, чтобы ваши абоненты по контракту использовали какой-то значимый идентификатор самоидентификации. – hiergiltdiestfu

ответ

6

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

StackTraceElement[] elements = Thread.currentThread().getStackTrace() 

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

+0

Наиболее полный ответ на случай использования без исключения, заданный в вопросе. Просто выведите первые пару элементов массива «elements» в удобном для вас формате. Слово предупреждения tho, Stacktraces ** исключительно ** дорого для вычисления.Вы смотрите на ухудшение характеристик на 4 порядка. Не используйте это для высокопроизводительных функций! Сделайте свое профилирование, затем положите эту идею в корзину и передайте некоторый идентификатор в качестве параметра. Затем каждый вызывающий абонент должен использовать какой-то аргумент self-id-ing для вызова этого метода по контракту. Не так удобно, но гораздо быстрее. – hiergiltdiestfu

+0

Производительность не является проблемой, потому что мы рассматриваем логические исключения, например, если в каком-либо разделе ссылки на приложение отсутствует идентификатор объекта, который не существует. Тогда мы можем прибить преступника. Я думаю, что, если вызывающий абонент идентифицирует себя, это добавленный слой связи, я бы скорее заплатил за производительность. – Mindwin

+0

Но ответ mikea очень изящный, я его озеленяю. – Mindwin

2

Этот метод отображает i строки трассировки стека, пропуская первые два.

public static String traceCaller(Exception ex, int i) { 
    StringWriter sw = new StringWriter(); 
    PrintWriter pw = new PrintWriter(sw); 
    StringBuilder sb = new StringBuilder(); 
    ex.printStackTrace(pw); 
    String ss = sw.toString(); 
    String[] splitted = ss.split("\n"); 
    sb.append("\n"); 
    if(splitted.length > 2 + i) { 
     for(int x = 2; x < i+2; x++) { 
      sb.append(splitted[x].trim()); 
      sb.append("\n"); 
     } 
     return sb.toString(); 
    } 
    return "Trace too Short."; 
} 

Первые две строки - это имя исключения и метод, который называется traceCaller(). Измените его, если вы хотите показать эти строки.

Спасибо пойти @BrianAgnew (stackoverflow.com/a/1149712/1532705) за идею StringWriter PrintWriter

+0

Благодарим вас за @BrianAgnew (http://stackoverflow.com/a/1149712/1532705) за идею 'StringWriter' PrintWriter'. – Mindwin

+0

IMO, вы должны переместить этот комментарий как часть своего ответа. –

+0

Ваш [(sic)] (http://en.wikipedia.org/wiki/Sic) Черт! – Mindwin

1

Если вы хотите укоротить трассировки стека, вы можете распечатать весь стек трассировки в StringWriter затем удалить то, что вы не хотите:

public static void main(String[] args) throws ParseException { 
    try { 
     throw new Exception("Argh!"); 
    } catch (Exception e) { 
     System.err.println(shortenedStackTrace(e, 1)); 
    } 
} 

public static String shortenedStackTrace(Exception e, int maxLines) { 
    StringWriter writer = new StringWriter(); 
    e.printStackTrace(new PrintWriter(writer)); 
    String[] lines = writer.toString().split("\n"); 
    StringBuilder sb = new StringBuilder(); 
    for (int i = 0; i < Math.min(lines.length, maxLines); i++) { 
     sb.append(lines[i]).append("\n"); 
    } 
    return sb.toString(); 
} 

в качестве альтернативы, использовать e.getStackTrace() для получения StackTraceElement[] массива. Это дает вам стек вызывающего абонента (от внутреннего к внешнему), но не сообщение об ошибке. Вам нужно будет использовать e.getMessage(), чтобы получить сообщение об ошибке.

Некоторые рамки ведения журнала могут быть сконфигурированы так, чтобы автоматически усекать трассировки стека. Например. см. this question and answer о конфигурации log4j.

Если вы просто хотите увидеть трассировки стека в любой точке в коде, вы можете получить элементы из Thread.currentThread() объекта:

Thread.currentThread().getStackTrace(); 
+0

«Без необходимости полагаться на внешние библиотеки» – Mindwin

3

Вы можете использовать ex.getStackTrace(), чтобы получить элементы стека, то StackTraceElement содержит одну строку полных стеков, затем распечатывайте, что хотите.

StackTraceElement[] elements = ex.getStackTrace(); 
print(elements[0]); 
Смежные вопросы