Quelle est la façon la plus simple de convertir le résultat de Throwable.getStackTrace()
en une chaîne qui représente le stacktrace?
Quelle est la façon la plus simple de convertir le résultat de Throwable.getStackTrace()
en une chaîne qui représente le stacktrace?
Réponses:
On peut utiliser la méthode suivante pour convertir une Exception
trace de pile en String
. Cette classe est disponible dans Apache commons-lang qui est la bibliothèque dépendante la plus courante avec de nombreuses sources ouvertes populaires
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)
org.apache.commons.lang3.exception.ExceptionUtils
.
Utilisez Throwable.printStackTrace(PrintWriter pw)
pour envoyer la trace de pile à un écrivain approprié.
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
et PrintWriter
?
Cela devrait fonctionner:
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
printStackTrace
devrait simplement renvoyer une chaîne, laissant la décision de l'imprimer ou non à l'utilisateur :)
printXXX()
devrait afficher XXX.
Si vous développez pour Android, un moyen beaucoup plus simple consiste à utiliser ceci:
import android.util.Log;
String stackTrace = Log.getStackTraceString(exception);
Le format est le même que getStacktrace, par exemple
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
Classe de goyaveSi vous avez l' Throwable
instance réelle , Google Guava fournit Throwables.getStackTraceAsString()
.
Exemple:
String s = Throwables.getStackTraceAsString ( myException ) ;
AVERTISSEMENT: n'inclut pas la cause (qui est généralement le bit utile!)
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")
ou quelque chose de similaire au lieu de "\n"
faire plaisir aux lamers DOS.
Pour moi, le moyen le plus propre et le plus simple était:
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
et PrintWriter
doivent être close
d ... (ou je suppose que seuls les PrintWriter
besoins doivent être fermés car la fermeture devrait fermer le StringWriter
trop)
Le code suivant vous permet d'obtenir l'intégralité de stackTrace avec un String
format, sans utiliser d'API comme log4J ou même 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.
}
Voici une version qui peut être copiée directement dans le code:
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());
Ou, dans un bloc de capture
} catch (Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
logger.info("Current stack trace is:\n" + sw.toString());
}
Throwable
est défini, non?
Arrays.toString(thrown.getStackTrace())
Est le moyen le plus simple de convertir le résultat en chaîne Je l'utilise dans mon programme pour imprimer la trace de la pile
LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});
Imprimez la trace de pile dans a PrintStream
, puis convertissez-la en a String
:
// ...
catch (Exception e)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(out));
String str = new String(out.toByteArray());
System.out.println(str);
}
Impression de la trace de pile dans une chaîne
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);
}
}
}
Il est utile lorsque vous souhaitez imprimer la trace de la pile de threads actuelle sans créer d'instance de Throwable
- mais notez que la création d'une nouvelle Throwable
trace de pile à partir de là est en fait plus rapide et moins coûteuse que d'appeler Thread.getStackTrace
.
private String getCurrentStackTraceString() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
return Arrays.stream(stackTrace).map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
}
Le tir intelligent dans la première série de commentaires a été très amusant, mais cela dépend vraiment de ce que vous essayez de faire. Si vous n'avez pas déjà la bonne bibliothèque, alors 3 lignes de code (comme dans la réponse de D. Wroblewski) sont parfaites. OTOH, si vous avez déjà la bibliothèque apache.commons (comme la plupart des grands projets), alors la réponse d'Amar est plus courte. OK, cela peut vous prendre dix minutes pour obtenir la bibliothèque et l'installer correctement (moins d'une si vous savez ce que vous faites). Mais l'horloge tourne, vous n'aurez donc peut-être pas de temps à perdre. Jarek Przygódzki avait une mise en garde intéressante - "Si vous n'avez pas besoin d'exceptions imbriquées".
Mais si je ne dois les traces de la pile complète, et tous imbriqués? Dans ce cas, le secret consiste à utiliser getFullStackTrace d'apache.common (voir http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html # getFullStackTrace% 28java.lang.Throwable% 29 )
Cela a sauvé mon bacon. Merci, Amar, pour l'astuce!
Code d' 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();
}
La différence avec les autres réponses est qu'il utilise autoFlush
sur le PrintWriter
.
Sans java.io.*
cela, cela peut se faire comme ça.
String trace = e.toString() + "\n";
for (StackTraceElement e1 : e.getStackTrace()) {
trace += "\t at " + e1.toString() + "\n";
}
Et puis le trace
variable contient votre trace de pile. La sortie contient également la cause initiale, la sortie est identique àprintStackTrace()
Exemple, printStackTrace()
donne:
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)
La trace
chaîne tient, lorsqu'elle est imprimée surstdout
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)
Version Scala
def stackTraceToString(e: Exception): String = {
import java.io.PrintWriter
val sw = new StringWriter()
e.printStackTrace(new PrintWriter(sw))
sw.toString
}
si vous utilisez Java 8, essayez ceci
Arrays.stream(e.getStackTrace())
.map(s->s.toString())
.collect(Collectors.joining("\n"));
vous pouvez trouver le code de getStackTrace()
fonction fourni par Throwable.java
:
public StackTraceElement[] getStackTrace() {
return getOurStackTrace().clone();
}
et pour StackTraceElement
, il fournit toString()
comme:
public String toString() {
return getClassName() + "." + methodName +
(isNativeMethod() ? "(Native Method)" :
(fileName != null && lineNumber >= 0 ?
"(" + fileName + ":" + lineNumber + ")" :
(fileName != null ? "("+fileName+")" : "(Unknown Source)")));
}
Il suffit donc de rejoindre le StackTraceElement
"\ n".
une extension de la réponse de Gala qui inclura également les causes de l'exception:
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;
}
La solution consiste à convertir le stackTrace du tableau en type de données chaîne . Voir l'exemple suivant:
import java.util.Arrays;
try{
}catch(Exception ex){
String stack = Arrays.toString(ex.getStackTrace());
System.out.println("stack "+ stack);
}
Avec l' API Java 8 Stream, vous pouvez faire quelque chose comme ceci:
Stream
.of(throwable.getStackTrace())
.map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
Il prendra un tableau d'oligo-éléments de pile, les convertira en chaîne et les joindra en chaîne multiligne.
Mon oneliner pour convertir la trace de la pile en la chaîne multiligne incluse:
Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))
Facile à transmettre à l'enregistreur "tel quel".
printStackTrace()
Ici, vous perdrez: 1) Exception qui a été levée; 2) Les causes et leur stacktrace
printStackTrace()
jamais fait partie de la question.
Si vous ne souhaitez pas utiliser une bibliothèque externe et que vous ne développez pas pour Android , vous pouvez créer une méthode d'extension comme celle-ci:
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();
}
Vieille question, mais je voudrais juste ajouter le cas spécial où vous ne voulez pas imprimer toute la pile , en supprimant certaines parties qui ne vous intéressent pas réellement, à l'exclusion de certaines classes ou packages.
Au lieu d'une PrintWriter
utilisation 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);
Lorsque la SelectivePrintWriter
classe est donnée par:
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);
}
}
}
Veuillez noter que cette classe peut être facilement adaptée pour filtrer par Regex contains
ou d'autres critères. Notez également que cela dépend des Throwable
détails de mise en œuvre (peu susceptibles de changer, mais quand même).
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);
}
}
}
Lorsque vous exécutez le programme, la sortie sera quelque chose de similaire:
java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)
Je me demande pourquoi personne n'a mentionné ExceptionUtils.getStackFrames(exception)
Pour moi, c'est le moyen le plus pratique de vider stacktrace avec toutes ses causes jusqu'à la fin:
String.join("\n", ExceptionUtils.getStackFrames(exception));
Attention: c'est peut-être un peu hors sujet, mais bon ...;)
Je ne sais pas quelle était la raison originale des affiches pour vouloir la trace de la pile comme chaîne en premier lieu. Lorsque la trace de pile doit se retrouver dans un journal SLF4J / Logback, mais qu'aucune exception n'a été ou ne devrait être levée, voici ce que je fais:
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
}
Je l'aime parce qu'il ne nécessite pas de bibliothèque externe (autre que votre backend de journalisation, qui sera bien sûr en place la plupart du temps).
Peu d'options
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Utilisation de Google Guava lib
String stackTrace = Throwables.getStackTraceAsString ( myException ) ;
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace (Throwable)