[java] ¿Cómo puedo convertir un trazado de pila en una cadena?



Answers

Utilice Throwable.printStackTrace (PrintWriter pw) para enviar el seguimiento de la pila a un escritor adecuado.

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);
Question

¿Cuál es la forma más fácil de convertir el resultado de Throwable.getStackTrace() en una cadena que representa la stacktrace?




Aquí hay una versión que puede copiarse directamente en el código:

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

O, en un bloque catch

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



La solución es convertir el stackTrace de la matriz al tipo de datos de cadena . Vea el siguiente ejemplo:

import java.util.Arrays;

try{

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






El siguiente código le permite obtener el stackTrace completo con un formato de String , sin utilizar API como log4J o incluso 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.
}



Si está desarrollando para Android, una forma mucho más fácil es usar esto:

import android.util.Log;

String stackTrace = Log.getStackTraceString(exception); 

El formato es el mismo que getStacktrace, por ejemplo

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)



Advertencia: esto puede estar un poco fuera de tema, pero bueno ...;)

No sé cuál era el motivo original de los carteles para querer rastrear la pila como cuerda en primer lugar. Cuando el seguimiento de la pila debe terminar en un SLF4J / Logback LOG, pero no se debe ni se debe lanzar una excepción, esto es lo que hago:

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
}

Me gusta porque no requiere una biblioteca externa (que no sea el servidor de inicio de sesión, que estará en su lugar la mayor parte del tiempo de todos modos, por supuesto).




El francotirador inteligente en el primer conjunto de comentarios fue muy divertido, pero realmente depende de lo que estás tratando de hacer. Si todavía no tienes la biblioteca correcta, entonces 3 líneas de código (como en la respuesta de D. Wroblewski) son perfectas. OTOH, si ya tienes la biblioteca apache.commons (como lo harán la mayoría de los proyectos grandes), entonces la respuesta de Amar es más corta. De acuerdo, puede tomar diez minutos obtener la biblioteca e instalarla correctamente (menos de uno si sabe lo que está haciendo). Pero el reloj sigue corriendo, por lo que es posible que no tenga tiempo de sobra. Jarek Przygódzki tenía una advertencia interesante: "Si no necesita excepciones anidadas".

Pero, ¿y si necesito los rastros de pila completos, anidados y todo? En ese caso, el secreto es usar getFullStackTrace de apache.common (ver http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html#getFullStackTrace%28java.lang.Throwable%29 )

Salvó mi tocino. Gracias, Amar, por la pista!




una exageración en la respuesta de Gala que también incluirá las causas de la excepció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;
}



Imprime stacktrace en PrintStream, luego conviértalo en String

// ...

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



Pregunta anterior, pero me gustaría agregar el caso especial donde no desea imprimir toda la pila , eliminando algunas partes que no le interesan, excluyendo ciertas clases o paquetes.

En lugar de un PrintWriter use 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);

Donde la clase SelectivePrintWriter está dada por:

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

Tenga en cuenta que esta clase se puede adaptar fácilmente para filtrar por Regex, contains u otros criterios. También tenga en cuenta que depende de los detalles de implementación Throwable (no es probable que cambie, pero aún así).




Sin java.io.* se puede hacer así.

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

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

Y luego la variable de trace contiene su traza de pila. La salida también tiene la causa inicial, la salida es idéntica a printStackTrace()

Ejemplo, printStackTrace() produce:

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)

El trace String se mantiene, cuando se imprime en 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)



Kotlin

La extensión de la clase Throwable le dará la propiedad String error.stackTraceString :

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





Links