Який найпростіший спосіб перетворити результат у Throwable.getStackTrace()
рядок, що зображає стеження?
Який найпростіший спосіб перетворити результат у Throwable.getStackTrace()
рядок, що зображає стеження?
Відповіді:
Для перетворення Exception
сліду стека можна скористатися наступним методом String
. Цей клас доступний в Apache commons-lang, який є найбільш поширеною залежною бібліотекою з багатьма популярними відкритими джерелами
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)
org.apache.commons.lang3.exception.ExceptionUtils
.
Використовуйте, Throwable.printStackTrace(PrintWriter pw)
щоб надіслати слід стека відповідному автору.
import java.io.StringWriter;
import java.io.PrintWriter;
// ...
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String sStackTrace = sw.toString(); // stack trace as a string
System.out.println(sStackTrace);
StringWriter
і PrintWriter
?
Це має працювати:
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
printStackTrace
повинно просто повернути рядок, залишаючи рішення про те, друкувати його чи ні користувачеві :)
printXXX()
повинен надрукувати XXX.
Якщо ви розробляєте для Android, набагато простішим способом є використання цього:
import android.util.Log;
String stackTrace = Log.getStackTraceString(exception);
Формат такий самий, як і getStacktrace, наприклад,
09-24 16:09:07.042: I/System.out(4844): java.lang.NullPointerException 09-24 16:09:07.042: I/System.out(4844): at com.temp.ttscancel.MainActivity.onCreate(MainActivity.java:43) 09-24 16:09:07.042: I/System.out(4844): at android.app.Activity.performCreate(Activity.java:5248) 09-24 16:09:07.043: I/System.out(4844): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110) 09-24 16:09:07.043: I/System.out(4844): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2162) 09-24 16:09:07.043: I/System.out(4844): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257) 09-24 16:09:07.043: I/System.out(4844): at android.app.ActivityThread.access$800(ActivityThread.java:139) 09-24 16:09:07.043: I/System.out(4844): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210) 09-24 16:09:07.043: I/System.out(4844): at android.os.Handler.dispatchMessage(Handler.java:102) 09-24 16:09:07.043: I/System.out(4844): at android.os.Looper.loop(Looper.java:136) 09-24 16:09:07.044: I/System.out(4844): at android.app.ActivityThread.main(ActivityThread.java:5097) 09-24 16:09:07.044: I/System.out(4844): at java.lang.reflect.Method.invokeNative(Native Method) 09-24 16:09:07.044: I/System.out(4844): at java.lang.reflect.Method.invoke(Method.java:515) 09-24 16:09:07.044: I/System.out(4844): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) 09-24 16:09:07.044: I/System.out(4844): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
Log.e("TAG", "My message", new Throwable());
Throwables
Клас ГуавиЯкщо у вас є фактичний Throwable
примірник, надає Google GuavaThrowables.getStackTraceAsString()
.
Приклад:
String s = Throwables.getStackTraceAsString ( myException ) ;
ПОПЕРЕДЖЕННЯ. Не включає причину (що зазвичай є корисним бітом!)
public String stackTraceToString(Throwable e) {
StringBuilder sb = new StringBuilder();
for (StackTraceElement element : e.getStackTrace()) {
sb.append(element.toString());
sb.append("\n");
}
return sb.toString();
}
String.format("%n")
або щось подібне замість того, "\n"
щоб зробити щасливими ламери DOS.
Для мене найчистішим і найпростішим способом було:
import java.util.Arrays;
Arrays.toString(e.getStackTrace());
public static String getStackTrace(Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
return sw.toString();
}
StringWriter
і PrintWriter
об'єкти повинні бути close
d .... (або я припускаю , що тільки PrintWriter
повинен бути закритий , так як закриття вона повинна закрити StringWriter
теж)
Наступний код дозволяє отримати весь stackTrace у String
форматі, не використовуючи такі API, як log4J або навіть java.util.Logger
:
catch (Exception e) {
StackTraceElement[] stack = e.getStackTrace();
String exception = "";
for (StackTraceElement s : stack) {
exception = exception + s.toString() + "\n\t\t";
}
System.out.println(exception);
// then you can send the exception string to a external file.
}
Ось версія, яку можна копіювати безпосередньо в код:
import java.io.StringWriter;
import java.io.PrintWriter;
//Two lines of code to get the exception into a StringWriter
StringWriter sw = new StringWriter();
new Throwable().printStackTrace(new PrintWriter(sw));
//And to actually print it
logger.info("Current stack trace is:\n" + sw.toString());
Або в блоці улову
} catch (Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
logger.info("Current stack trace is:\n" + sw.toString());
}
Throwable
визначено, правда?
Arrays.toString(thrown.getStackTrace())
Це найпростіший спосіб перетворення результату в String Я використовую це у своїй програмі для друку трасування стека
LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});
Роздрукуйте слід стека в a PrintStream
, а потім перетворіть його в String
:
// ...
catch (Exception e)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(out));
String str = new String(out.toByteArray());
System.out.println(str);
}
Друк сліду стека до рядка
import java.io.PrintWriter;
import java.io.StringWriter;
public class StackTraceUtils {
public static String stackTraceToString(StackTraceElement[] stackTrace) {
StringWriter sw = new StringWriter();
printStackTrace(stackTrace, new PrintWriter(sw));
return sw.toString();
}
public static void printStackTrace(StackTraceElement[] stackTrace, PrintWriter pw) {
for(StackTraceElement stackTraceEl : stackTrace) {
pw.println(stackTraceEl);
}
}
}
Це корисно, коли ви хочете надрукувати поточний слід стека потоку, не створюючи примірника, Throwable
- але зауважте, що створення нового Throwable
та отримання сліду стека насправді швидше та дешевше, ніж дзвінки Thread.getStackTrace
.
private String getCurrentStackTraceString() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
return Arrays.stream(stackTrace).map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
}
Розумний снайпер у першому наборі коментарів був дуже кумедним, але це дійсно залежить від того, що ви намагаєтеся зробити. Якщо ви ще не маєте правильної бібліотеки, то 3 рядки коду (як у відповіді Д. Врублевського) ідеально. ОТОХ, якщо у вас вже є бібліотека apache.commons (як і більшість великих проектів), відповідь Амара коротший. Гаразд, може знадобитися десять хвилин, щоб отримати бібліотеку та правильно встановити її (менше однієї, якщо ви знаєте, що ви робите). Але годинник тикає, тож, можливо, не вистачить часу на запас. У Jarek Przygódzki був цікавий застереження - "Якщо вам не потрібні вкладені винятки".
Але що робити, якщо мені потрібні цілі стеки стежок, вкладених і все? У цьому випадку секретом є використання apache.common’s getFullStackTrace (див. Http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html # getFullStackTrace% 28java.lang.Throwable% 29 )
Це врятувало моє бекон. Спасибі, Амар, за підказку!
Код від Apache Commons Lang 3.4 ( JavaDoc ):
public static String getStackTrace(final Throwable throwable) {
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw, true);
throwable.printStackTrace(pw);
return sw.getBuffer().toString();
}
Відмінність від інших відповідей полягає в тому, що він використовується autoFlush
на PrintWriter
.
Без java.io.*
цього можна обійтися так.
String trace = e.toString() + "\n";
for (StackTraceElement e1 : e.getStackTrace()) {
trace += "\t at " + e1.toString() + "\n";
}
І тоді trace
змінна утримує ваш слід стека. Вихід також містить початкову причину, вихід є ідентичнимprintStackTrace()
Приклад, printStackTrace()
урожайність:
java.io.FileNotFoundException: / (Is a directory)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
at Test.main(Test.java:9)
trace
Рядок виконується, коли друкуєтьсяstdout
java.io.FileNotFoundException: / (Is a directory)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
at Test.main(Test.java:9)
Версія Scala
def stackTraceToString(e: Exception): String = {
import java.io.PrintWriter
val sw = new StringWriter()
e.printStackTrace(new PrintWriter(sw))
sw.toString
}
якщо ви використовуєте Java 8, спробуйте це
Arrays.stream(e.getStackTrace())
.map(s->s.toString())
.collect(Collectors.joining("\n"));
Ви можете знайти код getStackTrace()
функції, який надає Throwable.java
:
public StackTraceElement[] getStackTrace() {
return getOurStackTrace().clone();
}
і для StackTraceElement
, він постачає toString()
як:
public String toString() {
return getClassName() + "." + methodName +
(isNativeMethod() ? "(Native Method)" :
(fileName != null && lineNumber >= 0 ?
"(" + fileName + ":" + lineNumber + ")" :
(fileName != null ? "("+fileName+")" : "(Unknown Source)")));
}
Тому просто приєднайтесь до StackTraceElement
"\ n".
експансія на відповідь Гали, яка також буде включати причини винятку:
private String extrapolateStackTrace(Exception ex) {
Throwable e = ex;
String trace = e.toString() + "\n";
for (StackTraceElement e1 : e.getStackTrace()) {
trace += "\t at " + e1.toString() + "\n";
}
while (e.getCause() != null) {
e = e.getCause();
trace += "Cause by: " + e.toString() + "\n";
for (StackTraceElement e1 : e.getStackTrace()) {
trace += "\t at " + e1.toString() + "\n";
}
}
return trace;
}
Рішення полягає в перетворенні матриці stackTrace в тип рядкових даних. Дивіться наступний приклад:
import java.util.Arrays;
try{
}catch(Exception ex){
String stack = Arrays.toString(ex.getStackTrace());
System.out.println("stack "+ stack);
}
За допомогою Java 8 Stream API ви можете зробити щось подібне:
Stream
.of(throwable.getStackTrace())
.map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
Це займе масив мікроелементів стека, перетворить їх у рядок і об'єднається в багаторядковий рядок.
Мій oneliner для перетворення сліду стека у додану рядок з декількома рядками:
Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))
Легко перейти до лісоруба "як є".
printStackTrace()
Тут ви втратите: 1) Виняток, який був кинутий; 2) Причини та їх стеження
printStackTrace()
ніколи не було частиною питання.
Якщо ви не хочете використовувати зовнішню бібліотеку і не розробляєте для Android , ви можете створити такий метод "розширення" :
public static String getStackTraceString(Throwable e) {
return getStackTraceString(e, "");
}
private static String getStackTraceString(Throwable e, String indent) {
StringBuilder sb = new StringBuilder();
sb.append(e.toString());
sb.append("\n");
StackTraceElement[] stack = e.getStackTrace();
if (stack != null) {
for (StackTraceElement stackTraceElement : stack) {
sb.append(indent);
sb.append("\tat ");
sb.append(stackTraceElement.toString());
sb.append("\n");
}
}
Throwable[] suppressedExceptions = e.getSuppressed();
// Print suppressed exceptions indented one level deeper.
if (suppressedExceptions != null) {
for (Throwable throwable : suppressedExceptions) {
sb.append(indent);
sb.append("\tSuppressed: ");
sb.append(getStackTraceString(throwable, indent + "\t"));
}
}
Throwable cause = e.getCause();
if (cause != null) {
sb.append(indent);
sb.append("Caused by: ");
sb.append(getStackTraceString(cause, indent));
}
return sb.toString();
}
Старе запитання, але я хотів би просто додати спеціальний корпус, коли ви не хочете надрукувати весь стек , видаливши деякі частини, які вас насправді не цікавлять, виключаючи певні класи чи пакети.
Замість PrintWriter
використання SelectivePrintWriter
:
// This filters out this package and up.
String packageNameToFilter = "org.springframework";
StringWriter sw = new StringWriter();
PrintWriter pw = new SelectivePrintWriter(sw, packageNameToFilter);
e.printStackTrace(pw);
String sStackTrace = sw.toString();
System.out.println(sStackTrace);
Де SelectivePrintWriter
клас задано:
public class SelectivePrintWriter extends PrintWriter {
private boolean on = true;
private static final String AT = "\tat";
private String internal;
public SelectivePrintWriter(Writer out, String packageOrClassName) {
super(out);
internal = "\tat " + packageOrClassName;
}
public void println(Object obj) {
if (obj instanceof String) {
String txt = (String) obj;
if (!txt.startsWith(AT)) on = true;
else if (txt.startsWith(internal)) on = false;
if (on) super.println(txt);
} else {
super.println(obj);
}
}
}
Зверніть увагу, що цей клас може бути легко адаптований до фільтрації за Regex contains
або іншими критеріями. Також зауважте, що це залежить від Throwable
деталей впровадження (можливо, це не зміниться, але все ж).
import java.io.PrintWriter;
import java.io.StringWriter;
public class PrintStackTrace {
public static void main(String[] args) {
try {
int division = 0 / 0;
} catch (ArithmeticException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
System.out.println(exceptionAsString);
}
}
}
Коли ви запускаєте програму, вихід буде чимось подібним:
java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)
Цікаво, чому ніхто не згадав ExceptionUtils.getStackFrames(exception)
Для мене це найзручніший спосіб скинути стеження з усіма його причинами до кінця:
String.join("\n", ExceptionUtils.getStackFrames(exception));
Попередження: Це може бути трохи поза темою, але ой добре ...;)
Я не знаю, в чому причина оригінальних плакатів полягала в тому, що в першу чергу хотілося простежити стек як рядок. Коли слід стека повинен опинитися в журналі SLF4J / Logback, але виняток не було або слід кидати ось що я роблю:
public void remove(List<String> ids) {
if(ids == null || ids.isEmpty()) {
LOG.warn(
"An empty list (or null) was passed to {}.remove(List). " +
"Clearly, this call is unneccessary, the caller should " +
"avoid making it. A stacktrace follows.",
getClass().getName(),
new Throwable ("Stacktrace")
);
return;
}
// actual work, remove stuff
}
Мені це подобається, тому що для нього не потрібна зовнішня бібліотека (крім вашого бекенда журналу, який, звичайно, буде на місці, як би там не було).
Мало варіантів
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Використовуючи Google Guava lib
String stackTrace = Throwables.getStackTraceAsString ( myException ) ;
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace (Throwable)