Question

Quelle est la meilleure façon de convertir le résultat de Throwable.getStackTrace() à une chaîne qui représente le stacktrace?

Était-ce utile?

La solution

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

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

Autres conseils

Utilisez Throwable.printStackTrace(PrintWriter pw) pour envoyer la trace de la 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);

Cela devrait fonctionner:

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

Si vous développez pour Android, d'une manière beaucoup plus facile est d'utiliser ceci:

import android.util.Log;

String stackTrace = Log.getStackTraceString(exception); 

Le format est le même que getStackTrace, pour 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)

Goyave de classe Throwables

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

Exemple:

String s = Throwables.getStackTraceAsString ( myException ) ;

AVERTISSEMENT: (! Ce qui est généralement le bit utile) Ne comprend pas la cause

public String stackTraceToString(Throwable e) {
    StringBuilder sb = new StringBuilder();
    for (StackTraceElement element : e.getStackTrace()) {
        sb.append(element.toString());
        sb.append("\n");
    }
    return sb.toString();
}

Pour moi, la plus propre et la plus simple est:

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

Le code suivant vous permet d'obtenir l'ensemble stackTrace avec un format String, sans utiliser des 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 est la copie pastable 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

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

Imprimer la trace de la pile à un PrintStream, puis le convertir en un String:

// ...

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

    System.out.println(str);
}

trace de pile d'impression à 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 voulez imprimer la trace actuelle de la pile de threads sans créer instance de Throwable -. Mais notez que la création de nouveaux Throwable et d'obtenir trace de la pile à partir de là est en fait que d'appeler Thread.getStackTrace plus vite et moins cher

Arrays.toString(thrown.getStackTrace())

est la meilleure façon de convertir le résultat en chaîne J'utilise dans mon programme d'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});

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()
  }
private String getCurrentStackTraceString() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    return Arrays.stream(stackTrace).map(StackTraceElement::toString)
            .collect(Collectors.joining("\n"));
}

Le sniping habile 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 l'avez pas déjà la bibliothèque correcte, puis 3 lignes de code (comme dans la réponse de D. Wroblewski) est parfait. OTOH, si vous avez déjà la bibliothèque apache.commons (comme la plupart des grands projets seront), puis la réponse de Amar est plus courte. OK, ça peut prendre dix minutes pour obtenir la bibliothèque et l'installer correctement (moins d'un si vous savez ce que vous faites). Mais le temps est compté, donc vous ne pouvez pas avoir le temps d'épargner. Jarek Przygodzki avait une mise en garde intéressante -. « Si vous n'avez pas besoin d'exceptions imbriquées »

Mais si je faire besoin des traces complètes de la pile, imbriquée et tout? Dans ce cas, le secret est d'utiliser getFullStackTrace de 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 )

Il a sauvé mon bacon. Merci, Amar, pour l'astuce!

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 que il utilise autoFlush sur le PrintWriter.

Sans java.io.* il 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 tient votre trace de la pile. Sortie détient également la cause initiale, la sortie est identique à printStackTrace()

exemple, les rendements 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)

La chaîne de trace contient, lors de l'impression à 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)

si vous utilisez Java 8, essayez ceci

Arrays.stream(e.getStackTrace())
                .map(s->s.toString())
                .collect(Collectors.joining("\n"));

vous pouvez trouver le code pour la fonction getStackTrace() fournie par Throwable.java comme:

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

et StackTraceElement, il toString() les fournisseurs 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 se joindre à la StackTraceElement avec "\ n".

un exapansion sur 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;
}

My oneliner convertir trace de la pile à la chaîne multi-ligne fermée:

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

Facile à passer à l'enregistreur « tel quel ».

La solution est pour convertir la matrice de stackTrace à 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);
}

La version Scala

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

Si vous ne souhaitez pas utiliser une bibliothèque externe et vous n'êtes pas le développement pour Android , vous pouvez créer un 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();
}

question ancienne, mais je voudrais juste ajouter le cas particulier où vous ne veulent pas imprimer toute la pile , en supprimant certaines parties que vous n'êtes pas réellement intéressé, à l'exclusion de certaines classes ou packages.

Au lieu d'un PrintWriter utiliser un 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 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);
        }
    }
}

S'il vous plaît noter que cette classe peut être facilement adapté pour filtrer par Regex, contains ou d'autres critères. Notez également qu'il dépend de détails de mise en œuvre de Throwable (ne sont pas 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)

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

Je ne sais pas ce que les affiches originales raison était de vouloir la trace de la pile sous forme de chaîne en premier lieu. Lorsque la trace de la pile doit se retrouver dans un SLF4J / Logback LOG, mais aucune exception a été ou devrait être jeté 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 une bibliothèque externe (autre que votre back-end de l'exploitation forestière, qui sera en place la plupart du temps de toute façon, bien sûr).

Peu d'options

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

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

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

J'ai écrit quelques méthodes pour cela il y a un certain temps, donc je me suis dit pourquoi ne pas jeter mes deux cents à ce sujet.

/** @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);
    ...
}

Prints:

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)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top