web-dev-qa-db-fra.com

Comment puis-je convertir une trace de pile en chaîne?

Quel est le moyen le plus simple de convertir le résultat de Throwable.getStackTrace() en une chaîne décrivant le stacktrace?

1316
ripper234

On peut utiliser la méthode suivante pour convertir une trace de pile Exception en String. Cette classe est disponible dans Apache commons-lang, la bibliothèque dépendante la plus courante avec de nombreuses sources ouvertes populaires

org.Apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)

921
amar

Utilisez Throwable.printStackTrace(PrintWriter pw) pour envoyer la trace de pile à un graveur 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);
2033
Brian Agnew

Cela devrait fonctionner: 

StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
426
D. Wroblewski

Si vous développez pour Android, un moyen bien 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)
193
Vicky Kapadia

Goyave Throwables class

Si vous avez l'instance Throwable réelle, Google Guava fournit Throwables.getStackTraceAsString() .

Exemple:

String s = Throwables.getStackTraceAsString ( myException ) ;
110
stumbav

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();
}
110
jqno

Pour moi, le moyen le plus propre et le plus simple était:

import Java.util.Arrays;
Arrays.toString(e.getStackTrace());
84
Vladas Diržys
public static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    return sw.toString();
}
29
Akira Yamamoto

Le code suivant vous permet d’obtenir la pile entière avec un format String, sans utiliser d’API telles que 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.
}
25
dumonderic

Voici une version qui est copier-coller 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

} catch (Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    logger.info("Current stack trace is:\n" + sw.toString());
}
19
rouble

Imprimez le stacktrace sur un PrintStream, puis convertissez-le en String

// ...

catch (Exception e)
{
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    e.printStackTrace(new PrintStream(out));
    String str = new String(out.toByteArray());

    System.out.println(str);
}
11
Baked Inhalf

Impression de la trace de la pile sur 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);
        }
    }
}

C'est utile lorsque vous souhaitez imprimer la trace de pile de thread actuelle sans créer l'instance de Throwable - mais notez que créer une nouvelle Throwable et obtenir une trace de pile à partir de là est en réalité plus rapide et moins coûteux que d'appeler Thread.getStackTrace.

11
private String getCurrentStackTraceString() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    return Arrays.stream(stackTrace).map(StackTraceElement::toString)
            .collect(Collectors.joining("\n"));
}
10
eddyrokr
Arrays.toString(thrown.getStackTrace())

Est le moyen le plus simple de convertir le résultat en String 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});
10
Ramanan Durairaj

Kotlin

L'extension de la classe Throwable vous donnera la propriété String error.stackTraceString:

val Throwable.stackTraceString: String
  get() {
    val sw = StringWriter()
    val pw = PrintWriter(sw)
    this.printStackTrace(pw)
    return sw.toString()
  }
9
vonox7

Le tir astucieux dans la première série de commentaires était très amusant, mais cela dépend vraiment de ce que vous essayez de faire. Si vous ne possédez pas déjà la bonne bibliothèque, 3 lignes de code (comme dans la réponse de D. Wroblewski) sont parfaites. ), alors la réponse d’Amar est plus brève… .. OK, cela peut vous prendre 10 minutes pour obtenir la bibliothèque et l’installer correctement (moins d’un si vous savez ce que vous faites). Mais le temps presse et vous n'avez peut-être pas le temps ... Jarek Przygódzki avait un avertissement intéressant: "Si vous n'avez pas besoin d'exceptions imbriquées".

Mais que se passe-t-il si je ai besoin des traces de pile complètes, imbriquées et toutes? Dans ce cas, le secret consiste à utiliser la méthode 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 m'a sauvé le bacon. Merci, Amar, pour cet indice!

9
Tihamer

Code de 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 que il utiliseautoFlush sur PrintWriter.

9
IvanRF

Sans Java.io.* cela peut être fait comme ça.

String trace = e.toString() + "\n";                     

for (StackTraceElement e1 : e.getStackTrace()) {
    trace += "\t at " + e1.toString() + "\n";
}   

Et puis la variable trace 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 chaîne trace est maintenue, lorsqu’elle est imprimée sur 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)
6
Gala

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 la fonction getStackTrace () fournie par Throwable.Java en tant que:

public StackTraceElement[] getStackTrace() {
    return getOurStackTrace().clone();
}

et pour StackTraceElement, il fournit toString en tant que:

public String toString() {
    return getClassName() + "." + methodName +
        (isNativeMethod() ? "(Native Method)" :
         (fileName != null && lineNumber >= 0 ?
          "(" + fileName + ":" + lineNumber + ")" :
          (fileName != null ?  "("+fileName+")" : "(Unknown Source)")));
}

Alors, rejoignez simplement StackTraceElement avec "\ n"

5
Pengcheng Zhang

un exemple de 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;
}
4
ido flax

La solution est pour convertir le stackTrace du tableau en chaîne type de données. Voir l'exemple suivant:

import Java.util.Arrays;

try{

}catch(Exception ex){
    String stack = Arrays.toString(ex.getStackTrace());
    System.out.println("stack "+ stack);
}
3
jorge santos

Mon oneliner pour convertir la trace de la pile en chaîne multiligne incluse:

Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))

Facile à transmettre à l’enregistreur "tel quel".

3
Andrey Lebedenko

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 'extension' comme ceci:

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();
}
2
Kapé
 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, le résultat sera similaire:

Java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.Java:9)
2
Prakhar Nigam

Ancienne question, mais je voudrais juste ajouter le cas particulier 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 de certains packages. 

Au lieu d'une PrintWriter, utilisez une 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);

Où la classe SelectivePrintWriter 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 détails de la mise en œuvre Throwable (peu susceptible de changer, mais quand même).

2
MarcG

Version Scala

def stackTraceToString(e: Exception): String = {
  import Java.io.PrintWriter
  val sw = new StringWriter()
  e.printStackTrace(new PrintWriter(sw))
  sw.toString
}
1
samthebest

J'ai écrit quelques méthodes pour cela il y a quelque temps, alors je me suis dit pourquoi ne pas jeter mes deux sous.

/** @param stackTraceElements The elements to convert
 * @return The resulting string */
public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements) {
    return stackTraceElementsToStr(stackTraceElements, "\n");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @return The resulting string */
public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements, String lineSeparator) {
    return stackTraceElementsToStr(stackTraceElements, lineSeparator, "");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting string */
public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements, String lineSeparator, String padding) {
    String str = "";
    if(stackTraceElements != null) {
        for(StackTraceElement stackTrace : stackTraceElements) {
            str += padding + (!stackTrace.toString().startsWith("Caused By") ? "\tat " : "") + stackTrace.toString() + lineSeparator;
        }
    }
    return str;
}

/** @param stackTraceElements The elements to convert
 * @return The resulting string */
public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements) {
    return stackTraceCausedByElementsOnlyToStr(stackTraceElements, "\n");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @return The resulting string */
public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements, String lineSeparator) {
    return stackTraceCausedByElementsOnlyToStr(stackTraceElements, lineSeparator, "");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting string */
public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements, String lineSeparator, String padding) {
    String str = "";
    if(stackTraceElements != null) {
        for(StackTraceElement stackTrace : stackTraceElements) {
            str += (!stackTrace.toString().startsWith("Caused By") ? "" : padding + stackTrace.toString() + lineSeparator);
        }
    }
    return str;
}

/** @param e The {@link Throwable} to convert
 * @return The resulting String */
public static final String throwableToStrNoStackTraces(Throwable e) {
    return throwableToStrNoStackTraces(e, "\n");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @return The resulting String */
public static final String throwableToStrNoStackTraces(Throwable e, String lineSeparator) {
    return throwableToStrNoStackTraces(e, lineSeparator, "");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting String */
public static final String throwableToStrNoStackTraces(Throwable e, String lineSeparator, String padding) {
    if(e == null) {
        return "null";
    }
    String str = e.getClass().getName() + ": ";
    if((e.getMessage() != null) && !e.getMessage().isEmpty()) {
        str += e.getMessage() + lineSeparator;
    } else {
        str += lineSeparator;
    }
    str += padding + stackTraceCausedByElementsOnlyToStr(e.getStackTrace(), lineSeparator, padding);
    for(Throwable suppressed : e.getSuppressed()) {
        str += padding + throwableToStrNoStackTraces(suppressed, lineSeparator, padding + "\t");
    }
    Throwable cause = e.getCause();
    while(cause != null) {
        str += padding + "Caused by:" + lineSeparator + throwableToStrNoStackTraces(e.getCause(), lineSeparator, padding);
        cause = cause.getCause();
    }
    return str;
}

/** @param e The {@link Throwable} to convert
 * @return The resulting String */
public static final String throwableToStr(Throwable e) {
    return throwableToStr(e, "\n");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @return The resulting String */
public static final String throwableToStr(Throwable e, String lineSeparator) {
    return throwableToStr(e, lineSeparator, "");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting String */
public static final String throwableToStr(Throwable e, String lineSeparator, String padding) {
    if(e == null) {
        return "null";
    }
    String str = padding + e.getClass().getName() + ": ";
    if((e.getMessage() != null) && !e.getMessage().isEmpty()) {
        str += e.getMessage() + lineSeparator;
    } else {
        str += lineSeparator;
    }
    str += padding + stackTraceElementsToStr(e.getStackTrace(), lineSeparator, padding);
    for(Throwable suppressed : e.getSuppressed()) {
        str += padding + "Suppressed: " + throwableToStr(suppressed, lineSeparator, padding + "\t");
    }
    Throwable cause = e.getCause();
    while(cause != null) {
        str += padding + "Caused by:" + lineSeparator + throwableToStr(e.getCause(), lineSeparator, padding);
        cause = cause.getCause();
    }
    return str;
}

Exemple:

try(InputStream in = new FileInputStream(file)) {
    ...
} catch(IOException e) {
    String exceptionToString = throwableToStr(e);
    someLoggingUtility.println(exceptionToString);
    ...
}

Impressions:

Java.io.FileNotFoundException: C:\test.txt (The system cannot find the file specified)
    at Java.io.FileInputStream.open0(Native Method)
    at Java.io.FileInputStream.open(Unknown Source)
    at Java.io.FileInputStream.<init>(Unknown Source)
    at com.gmail.br45entei.Example.main(Example.Java:32)
0
Brian_Entei

Attention: cela peut être un peu hors sujet, mais bon ...;)

Je ne sais pas ce que les affiches originales la raison étaient de vouloir la trace de pile en tant que chaîne en premier lieu. Lorsque la trace de la pile doit se retrouver dans un journal SLF4J/Logback, mais 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 bien parce qu’il n’exige pas de bibliothèque externe (autre que votre serveur de connexion, qui sera de toute façon en place la plupart du temps, bien sûr).

0
Alexander Wessel

Peu d'options

  1. StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); String exceptionAsString = sw.toString();

  2. Utilisation de Google Guava lib String stackTrace = Throwables.getStackTraceAsString ( myException ) ;

  3. org.Apache.commons.lang.exception.ExceptionUtils.getStackTrace (Throwable)

0
Eric