¿Cómo puedo obtener el seguimiento de la pila actual en Java?

1002

¿Cómo obtengo el seguimiento de la pila actual en Java, como en .NET que puede hacer?Environment.StackTrace ?

Encontré, Thread.dumpStack()pero no es lo que quiero, quiero recuperar el seguimiento de la pila, no imprimirlo.

ripper234
fuente
73
Siempre uso "new Exception (). PrintStackTrace ()" como expresión de observación cuando estoy depurando en Eclipse. Eso es útil cuando suspendes en un punto de quiebre y quieres saber de dónde vienes.
Tim Büthe el
22
@ TimBüthe: ¿Eclipse ya no te dice el seguimiento de pila cuando estás en modo de depuración? Creo que sí.
Luigi Massa Gallerano
41
Arrays.toString (Thread.currentThread (). GetStackTrace ()); Suficientemente simple.
Ajay
2
@Arkanon Se refiere a Java, y muestra cómo lo harían en .net y cuál es el equivalente en Java.
Pokechu22
99
Para imprimirlo bien, puede usar Apache StringUtils: StringUtils.join (currentThread (). GetStackTrace (), "\ n");
Arte

Respuestas:

1159

Puedes usar Thread.currentThread().getStackTrace().

Eso devuelve una matriz de StackTraceElements que representa la traza de pila actual de un programa.

jjnguy
fuente
48
Una frase divertida si ya está usando apache commons para obtener una cadena: String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
ripper234
55
El primer elemento (índice 0) en la matriz es el método java.lang.Thread.getStackTrace, el segundo (índice 1) generalmente es el primero de interés.
lilalinux
175
Un trazador de líneas para convertir el seguimiento de la pila en una cadena que funciona cuando no tiene una excepción y no está utilizando Apache Arrays.toString (Thread.currentThread (). GetStackTrace ())
Tony
99
La solución de @Tony es mejor porque no requiere un
lanzamiento
3
Como se señala en muchas respuestas a continuación: new Throwable().getStackTrace()es mucho más rápido, porque no necesita verificar this != Thread.currentThread()y omite los posibles gastos generales de JVM de llamarlo a través de child-class ( Exception extends Throwable)
Vlad
265
Thread.currentThread().getStackTrace();

está bien si no te importa cuál es el primer elemento de la pila.

new Throwable().getStackTrace();

tendrá una posición definida para su método actual, si eso es importante.

Yishai
fuente
35
(new Throwable()).getStackTrace()también se ejecuta más rápido (vea bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 )
MightyE
2
¿Puede explicar con más detalle cómo los resultados de Thread.currentThread (). GetStackTrace () pueden ser diferentes de los nuevos Throwable (). GetStackTrace ()? Intenté ambos y descubrí que Thread.currentThread (). GetStackTrace () devuelve una matriz con Thread.getStackTrace en el índice 0 y el método de llamada está en el índice 1. El nuevo método Throwable (). GetStackTrace () devuelve una matriz con la llamada método en el índice 0. Parece que ambos métodos tienen una posición definida para el método actual, pero las posiciones son diferentes. ¿Hay otra diferencia que estás señalando?
Ryan
99
@ Ryan, no hay garantía de que Thread.currentThread (). GetStackTrace () no prometa mantener esa posición en diferentes versiones del método. Entonces, cuando comprueba que estaba en el índice 1. En alguna versión de la JVM (1.5 o 1.6, no recuerdo) para Sun, era el índice 2. Eso es lo que quiero decir con una posición definida: la especificación requiere para estar allí y permanecer allí en el futuro.
Yishai
55
@MightyE El error ahora se informa como cerrado como corregido en Java 6. Al mirar las partes internas, parece que ahora lo hace (new Exception()).getStackTrace()cuando el seguimiento de la pila solicitada está en el hilo actual (que siempre será el caso paraThread.currentThread().getStackTrace();
M. Justin
3
@MJustin: el error no se informa "ahora" como solucionado, se ha solucionado incluso seis años antes de que MightyE escribiera el comentario. De hecho, se ha solucionado incluso antes de que se fundara Stackoverflow ...
Holger
181
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
    System.out.println(ste);
}
Leif Gruenwoldt
fuente
20
Java tiene un método printStackTrace definido en Throwable, puede hacer: new Exception().printStackTrace(System.out)lo que puedo recordar, el bucle for probablemente tenga menos sobrecarga, pero de todos modos solo debe usar esto como una depuración ...
Jaap
2
Este me gusta más porque tienes la oportunidad de eliminar el ruido, envolviendo tu declaración println, por ejemplofor (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
nby el
61
Thread.currentThread().getStackTrace();

está disponible desde JDK1.5.

Para una versión anterior, puede redirigir exception.printStackTrace()a StringWriter():

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
RealHowTo
fuente
3
new Throwable().getStackTrace()está disponible desde JDK1.4 ...
Holger
40

Puede usar los comunes de Apache para eso:

String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
stikkos
fuente
13
Esta es una buena solución de una línea. Para su información, para cualquiera que use org.apache.commons.lang3, la línea completa es:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
fileoffset
2
Solo para reiterar el comentario de fileoffset cuando me mudé a org.apache.commons.lang3, lo que inicialmente pasé por alto: la importación usa en lang3lugar de langy reemplaza getFullStackTracecon getStackTrace.
ggkmath
Eso es muy útil! Al depurar usando un IDE (por ejemplo, IntelliJ IDEA), es genial usar la ExceptionUtils.getStackTrace(new Throwable())expresión para obtener el seguimiento de la pila.
Sergey Brunov
24

En Android, una forma mucho más fácil es usar esto:

import android.util.Log;
String stackTrace = Log.getStackTraceString(exception); 
Vicky Kapadia
fuente
44
¿Dónde se define getStackTraceString? ¿Es de una biblioteca de registro de terceros?
skiphoppy
66
android.util.Log.getStackTraceString developer.android.com/reference/android/util/Log.html
Ondrej Kvasnovsky
22

Para obtener el seguimiento de la pila de todos los hilos, puede usar la utilidad jstack, JConsole o enviar una señal kill -quit (en un sistema operativo Posix).

Sin embargo, si desea hacer esto mediante programación, puede intentar usar ThreadMXBean:

ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] infos = bean.dumpAllThreads(true, true);

for (ThreadInfo info : infos) {
  StackTraceElement[] elems = info.getStackTrace();
  // Print out elements, etc.
}

Como se mencionó, si solo desea el seguimiento de la pila del hilo actual, es mucho más fácil: solo use Thread.currentThread().getStackTrace();

Adamski
fuente
2
El fragmento de código en esta respuesta se acerca más a la generación programática del tipo de volcado que ve al enviar a la JVM la señal QUIT (en sistemas similares a Unix) o <ctrl> <break> en Windows. A diferencia de las otras respuestas, puede ver monitores y sincronizadores, así como solo los seguimientos de la pila (por ejemplo, si itera sobre la matriz StackTraceElement y lo hace System.err.println(elems[i])en cada uno). Falta bean.la segunda línea del fragmento antes del, dumpAllThreadspero supongo que la mayoría de la gente podría resolverlo.
George Hawkins
22

Otra solución (solo 35 31 caracteres):

new Exception().printStackTrace();   
new Error().printStackTrace();
kukis
fuente
1
Impresionante solución. Ahora no tengo que recorrer todos los marcos de la pila
Vineel Kovvuri
17

Tonto yo, es Thread.currentThread().getStackTrace();

ripper234
fuente
17

Tony, como comentario a la respuesta aceptada, ha dado lo que parece ser la mejor respuesta que realmente responde a la pregunta del OP :

Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' );

... el OP NO preguntó cómo obtener un Stringseguimiento de la pila de un Exception. Y aunque soy un gran fanático de Apache Commons, cuando hay algo tan simple como lo anterior, no hay una razón lógica para usar una biblioteca externa.

Mike roedor
fuente
Tengo una lista de hilos y necesito imprimir sus rastros de pila.
Daneel S. Yaitskov
En ese caso, asegúrese de usar lo Thread.getAllStackTraces()que le da a Map<Thread, StackTraceElement[]>. Hotspot salvaguardará todos los subprocesos siempre que sea necesario. Zing puede llevar hilos individuales a un punto seguro sin molestar al otro. Obtener un stacktrace requiere un punto seguro. Thread.getAllStackTraces()obtiene todos los rastros de la pila y detiene todos los hilos solo una vez. Por supuesto, debes averiguar en qué mapeo estás realmente interesado.
Ralf H
14

Sugiero que

  Thread.dumpStack()

es una manera más fácil y tiene la ventaja de no construir realmente una excepción o lanzarla cuando puede que no haya ningún problema, y ​​es considerablemente más importante.

Thomas Adkins
fuente
1
Bien, en realidad, dumpStack () es un método estático, y se debe acceder de forma estática. Gracias eclipse!
Thomas Adkins
1
Me encanta el acceso directo, pero el código fuente de este método es: new Exception("Stack trace").printStackTrace();así que en realidad está construyendo un Throwable
Florent
13

Obteniendo stacktrace:

StackTraceElement[] ste = Thread.currentThread().getStackTrace();

Impresión de stacktrace (JAVA 8+):

Arrays.asList(ste).forEach(System.out::println);

Impresión de stacktrage (JAVA 7):

StringBuilder sb = new StringBuilder();

for (StackTraceElement st : ste) {
    sb.append(st.toString() + System.lineSeparator());
}
System.out.println(sb);
Witold Kaczurba
fuente
12

En Java 9 hay una nueva forma:

public static void showTrace() {

  List<StackFrame> frames =
    StackWalker.getInstance( Option.RETAIN_CLASS_REFERENCE )
               .walk( stream  -> stream.collect( Collectors.toList() ) );

  for ( StackFrame stackFrame : frames )
    System.out.println( stackFrame );
}
Christian Ullenboom
fuente
Interesante. :-)
djangofan
10

Tengo un método de utilidad que devuelve una cadena con el stacktrace:

static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw, true);
    t.printStackTrace(pw);
    pw.flush();
    sw.flush();
    return sw.toString();
}

Y solo logit como ...

... 
catch (FileNotFoundException e) {
    logger.config(getStackTrace(e));
}
Salvador Valencia
fuente
Esto parece un auto generado por Netbeans.
Leif Gruenwoldt
es logger un logger incorporado o uno que usted creó y escribió en un archivo.
Doug Hauf
@Doug Hauf, el registrador es una referencia al Constructor de Java incorporado. Asegúrese de configurar el archivo logging.properties. Agréguelo al comienzo de su clase de esta manera: Logger final estático privado logger = Logger.getLogger (Your_Class_Name.class.getName ());
Salvador Valencia
1
java.util.logging.Logger#log(Level, String, Throwable)Ya hace esto. Esto está reescribiendo cosas que ya existen en la biblioteca estándar de Java innecesariamente y está apuntando a los nuevos desarrolladores en la dirección incorrecta, que está lejos de la documentación. Al hacer esto ahora, ha obligado a Stacktrace a formatearse de cierta manera, ya que la loggingAPI le permite variar el formato de la instrucción de registro dinámicamente a medida que la especifica. Que yo sepa, log4jtambién tiene un comportamiento similar también. No reinventes la rueda porque terminas perdiendo cosas como te he explicado.
searchengine27
1
Existió en 2012 también. La fecha no hace una diferencia en su caso, desafortunadamente. Ver [enlace] (docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log (java.util.logging.Level, java.lang.String, java.lang .Throwable)), [link] (docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log (java.util.logging.LogRecord)), etc. (allí varias funciones que pasan a la Throwablefuera a los Handlers a través de las Formatters en 2012 que era Java7, más de lo que he enumerado aquí Y estas funciones se remontan mucho más tiempo que Java7 ha existido;. por lo tanto, J2SE 5.0 javadocs)
searchengine27
10

Para ensartar con guayaba:

Throwables.getStackTraceAsString(new Throwable())
Zitrax
fuente
8
try {
}
catch(Exception e) {
    StackTraceElement[] traceElements = e.getStackTrace();
    //...
}

o

Thread.currentThread().getStackTrace()
pollo de mantequilla
fuente
¿Su ejemplo principal no solo le dará el seguimiento de la pila en relación con el bloque try / catch?
Dan Monego 01 de
1
¿Cuáles son las diferencias entre los dos?
twlkyao
5

Quizás podrías intentar esto:

catch(Exception e)
{
    StringWriter writer = new StringWriter();
    PrintWriter pw = new PrintWriter(writer);
    e.printStackTrace(pw);
    String errorDetail = writer.toString();
}

La cadena 'errorDetail' contiene el stacktrace.

usuario1782556
fuente
5
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();

El último elemento de la matriz representa la parte inferior de la pila, que es la invocación de método menos reciente en la secuencia.

A StackTraceElement has getClassName(), getFileName(), getLineNumber() and getMethodName().

recorra StackTraceElement y obtenga el resultado deseado.

for (StackTraceElement ste : stackTraceElements ) 
{
    //do your stuff here...
}
Jawad Zeb
fuente
Gracias por mencionar que el último elemento contiene el más reciente. Contra-intuitivo y me ahorró algo de tiempo.
clearlight
también .toString () generará todos esos datos muy bien en una cadena
Vlad
4

Usé respuestas de arriba y agregué formato

public final class DebugUtil {

    private static final String SEPARATOR = "\n";

    private DebugUtil() {
    }

    public static String formatStackTrace(StackTraceElement[] stackTrace) {
        StringBuilder buffer = new StringBuilder();
        for (StackTraceElement element : stackTrace) {
            buffer.append(element).append(SEPARATOR);
        }
        return buffer.toString();
    }

    public static String formatCurrentStacktrace() {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        return formatStackTrace(stackTrace);
    }
}

fuente
2

Puede usar la utilidad jstack si desea verificar la pila de llamadas actual de su proceso.

Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message
Sampath
fuente
1

Esta es una publicación antigua, pero aquí está mi solución:

Thread.currentThread().dumpStack();

Más información y más métodos allí: http://javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html

Manov
fuente
3
Como Thread.dumpStack () es estático, solo debes llamarlo directamente.
David Avendasora
2
El OP indicó que desean una referencia en código para el seguimiento de la pila, no para imprimirlo.
Taylor R
1
Como @DavidAvendasora mencionó, debe llamar Thread.dumpStack()directamente porque es un método estático.
M-WaJeEh
Sí, java.lang.Thread.dumpStack () funciona en Java 11.
Park JongBum
-3

System.out.println(Arrays.toString(Thread.currentThread().getStackTrace()));

Esto lo ayudará a imprimir el seguimiento de la pila sin bucle.

Bhuvanwaitz
fuente
1
Su respuesta es la misma que la mía publicada 3 meses antes.
Mike roedor