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.
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.
Câu trả lời:
Bạn có thể dùng Thread.currentThread().getStackTrace()
.
Điều đó trả về một mảng StackTraceElement
s đại diện cho dấu vết ngăn xếp hiện tại của một chương trình.
String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e);
stackoverflow.com/a/10620951/11236
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
)
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.
(new Throwable()).getStackTrace()
cũng thực thi nhanh hơn (xem bug.sun.com/ormsdatabase/view_orms.do?orms_id=6375302 )
(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();
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
System.out.println(ste);
}
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 ...
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
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();
new Throwable().getStackTrace()
có sẵn kể từ JDK1.4,
Bạn có thể sử dụng commons của Apache cho điều đó:
String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
org.apache.commons.lang3
, dòng đầy đủ là:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
org.apache.commons.lang3
, mà ban đầu tôi đã bỏ qua - việc nhập sử dụng lang3
thay vì lang
và thay thế getFullStackTrace
bằng getStackTrace
.
ExceptionUtils.getStackTrace(new Throwable())
biểu thức để lấy dấu vết ngăn xếp.
Trên Android một cách dễ dàng hơn nhiều là sử dụng điều này:
import android.util.Log;
String stackTrace = Log.getStackTraceString(exception);
Để 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()
;
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 dumpAllThreads
nhưng tôi đoán hầu hết mọi người có thể làm việc đó.
Một giải pháp khác (chỉ có 35 31 ký tự):
new Exception().printStackTrace();
new Error().printStackTrace();
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 String
dấ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.
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.
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.
new Exception("Stack trace").printStackTrace();
vì vậy nó thực sự xây dựng một Ném được
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);
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 );
}
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));
}
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 đó logging
API 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, log4j
cũ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.
Throwable
cho Handler
s đến Formatter
nă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)
try {
}
catch(Exception e) {
StackTraceElement[] traceElements = e.getStackTrace();
//...
}
hoặc là
Thread.currentThread().getStackTrace()
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.
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...
}
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);
}
}
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
Đâ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
Thread.dumpStack()
trực tiếp vì phương thức tĩnh của nó.
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.