Làm cách nào tôi có thể theo dõi ngăn xếp hiện tại trong Java?


1002

Làm cách nào để có được dấu vết ngăn xếp hiện tại trong Java, như cách bạn có thể làm trong .NET Environment.StackTrace?

Tôi đã tìm thấy Thread.dumpStack()nhưng đó không phải là điều tôi muốn - tôi muốn lấy lại dấu vết ngăn xếp, không in nó ra.


73
Tôi luôn sử dụng "ngoại lệ mới (). PrintStackTrace ()" làm biểu thức đồng hồ khi tôi gỡ lỗi trong Eclipse. Điều đó thật hữu ích khi bạn tạm dừng tại một điểm dừng và muốn biết bạn đến từ đâu.
Tim Büthe

22
@ TimBüthe: không phải Eclipse đã cho bạn biết Stack Trace khi bạn ở chế độ gỡ lỗi? Tôi nghĩ vậy.
Luigi Massa Gallerano

41
Arrays.toString (Thread.cienThread (). GetStackTrace ()); đủ đơn giản.
Ajay

2
@Arkanon Nó đề cập đến java và đang chỉ ra cách họ sẽ làm điều đó trong .net và những gì tương đương trong java.
Pokechu22

9
Để in độc đáo, bạn có thể sử dụng apache StringUtils: StringUtils.join (currentThread (). GetStackTrace (), "\ n");
Nghệ thuật

Câu trả lời:


1159

Bạn có thể dùng Thread.currentThread().getStackTrace() .

Điều đó trả về một mảng StackTraceElements đại diện cho dấu vết ngăn xếp hiện tại của một chương trình.


48
Một lớp lót thú vị nếu bạn đang sử dụng dấu phẩy apache để lấy chuỗi: String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
ripper234

5
Phần tử đầu tiên (chỉ số 0) trong mảng là phương thức java.lang.Thread.getStackTrace, phần thứ hai (chỉ mục 1) thường là phần đầu tiên được quan tâm.
lilalinux

175
Một lớp lót để chuyển đổi dấu vết ngăn xếp thành một chuỗi hoạt động khi bạn không có ngoại lệ và bạn không sử dụng Apache Arrays.toString (Thread.cienThread (). GetStackTrace ())
Tony

9
Giải pháp của @Tony tốt hơn bởi vì nó không yêu cầu có thể ném được
mvd

3
Như đã chỉ ra trong nhiều câu trả lời dưới đây - new Throwable().getStackTrace()nhanh hơn nhiều, vì không cần phải kiểm tra this != Thread.currentThread()và bỏ qua các chi phí JVM tiềm năng khi gọi nó thông qua lớp trẻ em ( Exception extends Throwable)
Vlad

264
Thread.currentThread().getStackTrace();

sẽ ổn nếu bạn không quan tâm yếu tố đầu tiên của ngăn xếp là gì.

new Throwable().getStackTrace();

sẽ có một vị trí xác định cho phương thức hiện tại của bạn, nếu điều đó quan trọng.


35
(new Throwable()).getStackTrace()cũng thực thi nhanh hơn (xem bug.sun.com/ormsdatabase/view_orms.do?orms_id=6375302 )
MightyE

2
Bạn có thể giải thích chi tiết hơn về kết quả của Thread.cienThread (). GetStackTrace () có thể khác với throwable (). GetStackTrace () không? Tôi đã thử cả hai và thấy rằng Thread.cienThread (). GetStackTrace () trả về mảng với Thread.getStackTrace trong chỉ mục 0 và phương thức gọi là ở chỉ mục 1. Phương thức throwable (). GetStackTrace () mới trả về một mảng với lệnh gọi phương thức tại chỉ số 0. Có vẻ như cả hai phương thức đều có một vị trí xác định cho phương thức hiện tại nhưng các vị trí khác nhau. Có sự khác biệt nào bạn đang chỉ ra?
Ryan

9
@Ryan, không có gì đảm bảo rằng Thread.cienThread (). GetStackTrace () không hứa sẽ duy trì vị trí đó trên các phiên bản khác nhau của phương thức. Vì vậy, khi bạn tình cờ kiểm tra nó ở chỉ số 1. Trên một số phiên bản JVM (1.5 hoặc 1.6, đừng nhớ) cho Sun, đó là chỉ số 2. Đó là ý nghĩa của một vị trí được xác định - thông số kỹ thuật gọi cho nó sẽ ở đó và ở đó trong tương lai.
Yishai

5
@MightyE Lỗi hiện được báo cáo là đã đóng như đã sửa trong Java 6. Nhìn vào phần bên trong, có vẻ như bây giờ xảy ra (new Exception()).getStackTrace()khi dấu vết ngăn xếp được yêu cầu nằm trên luồng hiện tại (sẽ luôn là trường hợp củaThread.currentThread().getStackTrace();
M. Justin

3
@MJustin: lỗi không phải là ngay bây giờ, báo cáo là lỗi đã được sửa, nó đã được sửa ngay cả sáu năm trước khi MightyE viết bình luận. Trên thực tế, nó đã được sửa ngay cả trước khi Stackoverflow được thành lập Tập
Holger

181
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
    System.out.println(ste);
}

20
java có một phương thức printStackTrace được định nghĩa trên throwable, bạn có thể làm: new Exception().printStackTrace(System.out)điều mà tôi có thể nhớ, vòng lặp for có thể có ít chi phí hơn, nhưng dù sao bạn cũng chỉ nên sử dụng nó như một thứ gỡ lỗi ...
Jaap

2
Tôi như thế này một tốt nhất bởi vì bạn sẽ có được một cơ hội để loại bỏ tiếng ồn, bởi gói tuyên bố println của bạn, ví dụ:for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
nTheo

61
Thread.currentThread().getStackTrace();

có sẵn kể từ JDK1.5.

Đối với phiên bản cũ hơn, bạn có thể chuyển hướng exception.printStackTrace()đến StringWriter():

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();

3
new Throwable().getStackTrace()có sẵn kể từ JDK1.4,
Holger

40

Bạn có thể sử dụng commons của Apache cho điều đó:

String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);

13
Đây là một giải pháp một dòng tốt đẹp. FYI, cho bất cứ ai sử dụng org.apache.commons.lang3, dòng đầy đủ là:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
tập tin khởi động

2
Chỉ để nhắc lại nhận xét của tập tin tập tin khi chuyển đến org.apache.commons.lang3, mà ban đầu tôi đã bỏ qua - việc nhập sử dụng lang3thay vì langvà thay thế getFullStackTracebằng getStackTrace.
ggkmath

Điều đó rất hữu ích! Khi gỡ lỗi bằng IDE (ví dụ IntelliJ IDEA), thật tuyệt khi sử dụng ExceptionUtils.getStackTrace(new Throwable())biểu thức để lấy dấu vết ngăn xếp.
Sergey Brunov


22

Để có được dấu vết ngăn xếp của tất cả các luồng, bạn có thể sử dụng tiện ích jstack, JConsole hoặc gửi tín hiệu diệt muỗi (trên hệ điều hành Posix).

Tuy nhiên, nếu bạn muốn thực hiện việc này theo lập trình, bạn có thể thử sử dụng ThreadMXBean:

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

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

Như đã đề cập, nếu bạn chỉ muốn theo dõi ngăn xếp của luồng hiện tại thì dễ dàng hơn nhiều - Chỉ cần sử dụng Thread.currentThread().getStackTrace();


2
Đoạn mã trong câu trả lời này gần nhất với việc tạo ra loại kết xuất mà bạn thấy khi gửi tín hiệu QUVM (trên hệ thống giống như Unix) hoặc <ctrl> <break> trên Windows. Không giống như các câu trả lời khác, bạn có thể xem màn hình và đồng bộ hóa cũng như chỉ dấu vết ngăn xếp (ví dụ: nếu bạn lặp qua mảng StackTraceEuity và thực hiện System.err.println(elems[i])trên từng màn hình). Dòng thứ hai trong đoạn trích bị thiếu bean.trước dumpAllThreadsnhưng tôi đoán hầu hết mọi người có thể làm việc đó.
George Hawkins

22

Một giải pháp khác (chỉ có 35 31 ký tự):

new Exception().printStackTrace();   
new Error().printStackTrace();

1
giải pháp tuyệt vời. Bây giờ tôi không phải lặp qua tất cả các khung stack
Vineel Kovvuri

17

Ngớ ngẩn với tôi, nó Thread.currentThread().getStackTrace();


17

Tony, như một bình luận cho câu trả lời được chấp nhận, đã đưa ra câu trả lời có vẻ là câu trả lời hay nhất thực sự trả lời câu hỏi của OP :

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

... OP KHÔNG hỏi làm thế nào để có được một Stringdấu vết từ ngăn xếp từ một Exception. Và mặc dù tôi là một fan hâm mộ lớn của Apache Commons, khi có một thứ đơn giản như ở trên thì không có lý do hợp lý nào để sử dụng một thư viện bên ngoài.


Tôi có một danh sách các chủ đề và tôi cần in dấu vết ngăn xếp của chúng.
Daneel S. Yaitskov

Trong trường hợp đó, hãy chắc chắn rằng bạn sử dụng Thread.getAllStackTraces()nó mang lại cho bạn a Map<Thread, StackTraceElement[]>. Hotspot sẽ bảo vệ tất cả các chủ đề bất cứ khi nào nó cần để bảo vệ một chủ đề. Zing có thể mang các chủ đề riêng lẻ đến một điểm an toàn mà không làm phiền người khác. Bắt một stacktrace đòi hỏi một điểm an toàn. Thread.getAllStackTraces()được tất cả các dấu vết ngăn xếp và dừng tất cả các chủ đề chỉ một lần. Tất nhiên, bạn phải tìm ra bản đồ nào bạn thực sự quan tâm.
Ralf H

14

Tôi khẳng định rằng

  Thread.dumpStack()

là một cách dễ dàng hơn và có lợi thế là không thực sự xây dựng một ngoại lệ hoặc có thể ném được khi có thể không có vấn đề gì cả, và đáng kể hơn nhiều.


1
Được rồi, thực sự, dumpStack () là một phương thức tĩnh và nên được truy cập theo cách tĩnh. Cảm ơn, nhật thực!
Thomas Adkins

1
Tôi thích lối tắt, nhưng mã nguồn của phương pháp này là: new Exception("Stack trace").printStackTrace();vì vậy nó thực sự xây dựng một Ném được
Florent

13

Bắt stacktrace:

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

In ngăn xếp (JAVA 8+):

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

In stacktrage (JAVA 7):

StringBuilder sb = new StringBuilder();

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

12

Trong Java 9 có một cách mới:

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

Hấp dẫn. :-)
djangofan

10

Tôi có một phương thức tiện ích trả về một chuỗi với 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();
}

Và chỉ cần đăng nhập như ...

... 
catch (FileNotFoundException e) {
    logger.config(getStackTrace(e));
}

Điều này trông giống như một tự động được tạo ra bởi Netbeans.
Leif Gruenwoldt

là logger một logger tích hợp hoặc một cái mà bạn đã tạo và ghi vào một tệp.
Doug Hauf

@Doug Hauf, logger là một tham chiếu đến Java Logger tích hợp. Hãy chắc chắn rằng bạn định cấu hình tệp log.properIES. Thêm nó vào đầu lớp của bạn như thế này: private static Logger logger = Logger.getLogger (Your_Class_Name. Class.getName ());
Salvador Valencia

1
java.util.logging.Logger#log(Level, String, Throwable)đã làm điều này. Điều này đang viết lại những thứ đã tồn tại trong thư viện tiêu chuẩn Java một cách không cần thiết và đang chỉ ra các nhà phát triển mới đi sai hướng, nằm ngoài tài liệu. Bằng cách này, bạn đã buộc Stacktrace được định dạng theo một cách nhất định, trong đó loggingAPI cho phép bạn thay đổi định dạng của câu lệnh nhật ký một cách linh hoạt khi bạn chỉ định nó. Theo hiểu biết của tôi, log4jcũng có hành vi tương tự là tốt. Đừng phát minh lại bánh xe vì cuối cùng bạn sẽ mất những thứ như tôi đã giải thích.
searchengine27

1
Nó tồn tại vào năm 2012. Thật không may, ngày không có sự khác biệt trong trường hợp của bạn. Xem [link] (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)), v.v (có là một số hàm chuyển giao Throwablecho Handlers đến Formatternăm 2012 là Java7, nhiều hơn tôi đã liệt kê ở đây. Và các hàm này có niên đại lâu hơn Java7, do đó J2SE 5.0 javadocs)
searchengine27

10

Để xâu chuỗi với ổi:

Throwables.getStackTraceAsString(new Throwable())

8
try {
}
catch(Exception e) {
    StackTraceElement[] traceElements = e.getStackTrace();
    //...
}

hoặc là

Thread.currentThread().getStackTrace()

Ví dụ hàng đầu của bạn không chỉ cung cấp cho bạn dấu vết ngăn xếp liên quan đến khối thử / bắt?
Dan Monego

1
sự khác biệt giữa hai
twlkyao

5

Có lẽ bạn có thể thử điều này:

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

Chuỗi 'errorDetail' chứa stacktrace.


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

Phần tử cuối cùng của mảng biểu thị phần dưới cùng của ngăn xếp, đây là cách gọi phương thức gần đây nhất trong chuỗi.

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

lặp qua StackTraceEuity và nhận kết quả mong muốn của bạn.

for (StackTraceElement ste : stackTraceElements ) 
{
    //do your stuff here...
}

Cảm ơn đã đề cập đến yếu tố cuối cùng chứa gần đây nhất. Phản trực giác và tiết kiệm cho tôi một thời gian.
chiếu sáng

đồng thời .toString () sẽ xuất tất cả dữ liệu đó thành một chuỗi
Vlad

4

Tôi đã sử dụng câu trả lời từ trên và thêm định dạng

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

2

Bạn có thể sử dụng tiện ích jstack nếu bạn muốn kiểm tra ngăn xếp cuộc gọi hiện tại của quy trình của mình.

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

1

Đây là một bài viết cũ, nhưng đây là giải pháp của tôi:

Thread.currentThread().dumpStack();

Thêm thông tin và nhiều phương pháp khác tại đó: http://javarevisited.blogspot.fr/2013/04/how-to-get-civerse-stack-trace-in-java-thread.html


3
Vì Thread.dumpStack () là tĩnh, bạn chỉ cần gọi trực tiếp.
David Avendasora

2
OP chỉ ra rằng họ muốn một tham chiếu trong mã đến theo dõi ngăn xếp, không in nó ra.
Taylor R

1
như @DavidAvendasora đã đề cập, bạn nên gọi Thread.dumpStack()trực tiếp vì phương thức tĩnh của nó.
M-WaJeEh

Có, java.lang.Thread.dumpStack () hoạt động trên Java 11.
Park JongBum

-3

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

Điều này sẽ giúp bạn in dấu vết ngăn xếp mà không cần vòng lặp.


1
Câu trả lời của bạn giống như của tôi được đăng 3 tháng trước.
mike gặm nhấm
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.