¿Cuál es la forma más fácil de convertir el resultado de Throwable.getStackTrace()
a una cadena que representa el stacktrace?
¿Cuál es la forma más fácil de convertir el resultado de Throwable.getStackTrace()
a una cadena que representa el stacktrace?
Respuestas:
Se puede usar el siguiente método para convertir un Exception
seguimiento de pila String
. Esta clase está disponible en Apache commons-lang, que es la biblioteca dependiente más común con muchas fuentes abiertas populares
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)
org.apache.commons.lang3.exception.ExceptionUtils
.
Se usa Throwable.printStackTrace(PrintWriter pw)
para enviar el seguimiento de la pila a un escritor apropiado.
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
y PrintWriter
?
Esto debería funcionar:
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
printStackTrace
debería devolver la cadena, dejando la decisión de si imprimirla o no al usuario :)
printXXX()
debería imprimir XXX.
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)
Log.e("TAG", "My message", new Throwable());
Throwables
Clase de guayabaSi tiene la Throwable
instancia real , Google Guava proporciona Throwables.getStackTraceAsString()
.
Ejemplo:
String s = Throwables.getStackTraceAsString ( myException ) ;
ADVERTENCIA: no incluye la causa (que generalmente es el bit útil)
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")
algo similar en lugar de "\n"
hacer felices a los lamers de DOS.
Para mí, la forma más limpia y fácil fue:
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
y PrintWriter
deberían ser close
d ... (o supongo que solo PrintWriter
es necesario cerrarlos, ya que cerrarlos también debería cerrarlos StringWriter
)
El siguiente código le permite obtener todo el stackTrace con un String
formato, 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.
}
Aquí hay una versión que se puede copiar y pegar 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 de captura
} catch (Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
logger.info("Current stack trace is:\n" + sw.toString());
}
Throwable
se define el, ¿verdad?
Arrays.toString(thrown.getStackTrace())
Es la forma más fácil de convertir el resultado en Cadena. Estoy usando esto en mi programa para imprimir el seguimiento de la pila.
LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});
Imprima el seguimiento de la pila en a PrintStream
, luego conviértalo a String
:
// ...
catch (Exception e)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(out));
String str = new String(out.toByteArray());
System.out.println(str);
}
Impresión de seguimiento de pila a cadena
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);
}
}
}
Es útil cuando desea imprimir el seguimiento de la pila de subprocesos actual sin crear una instancia de Throwable
, pero tenga en cuenta que crear un nuevo Throwable
y obtener el seguimiento de la pila desde allí en realidad es más rápido y más barato que llamar Thread.getStackTrace
.
private String getCurrentStackTraceString() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
return Arrays.stream(stackTrace).map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
}
Los disparos inteligentes en el primer conjunto de comentarios fueron muy divertidos, pero realmente dependen de lo que intentes hacer. Si aún no tiene la biblioteca correcta, entonces 3 líneas de código (como en la respuesta de D. Wroblewski) son perfectas. OTOH, si ya tiene 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 llevarle diez minutos obtener la biblioteca e instalarla correctamente (menos de uno si sabe lo que está haciendo). Pero el tiempo corre, 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 yo no necesito los seguimientos de pila completos, anidados y todo? En ese caso, el secreto es usar getFullStackTrace de apache.common (consulte http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html # getFullStackTrace% 28java.lang.Throwable% 29 )
Me salvó el tocino. Gracias, Amar, por la pista!
Código 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 diferencia con las otras respuestas es que se usa autoFlush
en el PrintWriter
.
Sin java.io.*
eso se puede hacer así.
String trace = e.toString() + "\n";
for (StackTraceElement e1 : e.getStackTrace()) {
trace += "\t at " + e1.toString() + "\n";
}
Y luego la trace
variable contiene su rastro de pila. La salida también tiene la causa inicial, la salida es idéntica aprintStackTrace()
Ejemplo, printStackTrace()
rendimientos:
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
cadena se mantiene, cuando se imprime enstdout
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)
Versión Scala
def stackTraceToString(e: Exception): String = {
import java.io.PrintWriter
val sw = new StringWriter()
e.printStackTrace(new PrintWriter(sw))
sw.toString
}
si está utilizando Java 8, intente esto
Arrays.stream(e.getStackTrace())
.map(s->s.toString())
.collect(Collectors.joining("\n"));
Puede encontrar el código para la getStackTrace()
función proporcionado por Throwable.java
:
public StackTraceElement[] getStackTrace() {
return getOurStackTrace().clone();
}
y para StackTraceElement
proveedores toString()
como:
public String toString() {
return getClassName() + "." + methodName +
(isNativeMethod() ? "(Native Method)" :
(fileName != null && lineNumber >= 0 ?
"(" + fileName + ":" + lineNumber + ")" :
(fileName != null ? "("+fileName+")" : "(Unknown Source)")));
}
Así que solo únete StackTraceElement
con "\ n".
una exapansió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;
}
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);
}
Con Java 8 Stream API puedes hacer algo como esto:
Stream
.of(throwable.getStackTrace())
.map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
Tomará una variedad de elementos traza de la pila, los convertirá en una cadena y se unirá en una cadena multilínea.
Mi línea para convertir el seguimiento de la pila a la cadena de varias líneas adjunta:
Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))
Fácil de pasar al registrador "tal cual".
printStackTrace()
Aquí perderás: 1) Excepción que se lanzó; 2) Causas y su stacktrace
printStackTrace()
nunca fue parte de la pregunta.
Si no desea utilizar una biblioteca externa y no está desarrollando para Android , puede crear un método de 'extensión' como este:
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();
}
Antigua pregunta, pero me gustaría agregar el caso especial en el que no desea imprimir toda la pila , eliminando algunas partes que realmente no le interesan, excluyendo ciertas clases o paquetes.
En lugar de PrintWriter
usar a 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 SelectivePrintWriter
clase 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 Throwable
detalles de implementación (no es probable que cambie, pero aún así).
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);
}
}
}
Cuando ejecutas el programa, la salida será algo similar:
java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)
Me pregunto por qué nadie mencionó ExceptionUtils.getStackFrames(exception)
Para mí es la forma más conveniente de volcar stacktrace con todas sus causas hasta el final:
String.join("\n", ExceptionUtils.getStackFrames(exception));
Advertencia: Esto puede estar un poco fuera de tema, pero bueno ...;)
No sé cuál fue la razón original de los carteles para querer el seguimiento de la pila como cadena en primer lugar. Cuando la traza de la pila debería terminar en un REGISTRO SLF4J / Logback, pero no se produjo ni se debe hacer 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 su backend de registro, que de todos modos estará en su lugar la mayor parte del tiempo, por supuesto).
Pocas opciones
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Usando Google Guava lib
String stackTrace = Throwables.getStackTraceAsString ( myException ) ;
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace (Throwable)