Cách dễ nhất để chuyển đổi kết quả của Throwable.getStackTrace()
một chuỗi mô tả stacktrace là gì?
Cách dễ nhất để chuyển đổi kết quả của Throwable.getStackTrace()
một chuỗi mô tả stacktrace là gì?
Câu trả lời:
Người ta có thể sử dụng phương pháp sau để chuyển đổi Exception
dấu vết ngăn xếp thành String
. Lớp này có sẵn trong Apache commons-lang, thư viện phụ thuộc phổ biến nhất với nhiều nguồn mở phổ biến
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)
org.apache.commons.lang3.exception.ExceptionUtils
.
Sử dụng Throwable.printStackTrace(PrintWriter pw)
để gửi theo dõi ngăn xếp cho một nhà văn thích hợp.
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
và PrintWriter
không?
Điều này sẽ làm việc:
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
printStackTrace
chỉ nên trả về chuỗi, để lại quyết định về việc in hay không cho người dùng :)
printXXX()
nên in XXX.
Nếu bạn đang phát triển cho 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);
Định dạng giống như getStacktrace, ví dụ:
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
Lớp ổiNếu bạn có Throwable
ví dụ thực tế , Google Guava cung cấp Throwables.getStackTraceAsString()
.
Thí dụ:
String s = Throwables.getStackTraceAsString ( myException ) ;
CẢNH BÁO: Không bao gồm nguyên nhân (thường là bit hữu ích!)
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")
hoặc một cái gì đó tương tự thay vì "\n"
làm cho DOS than phiền.
Đối với tôi cách sạch nhất và dễ nhất là:
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
và PrintWriter
các đối tượng phải là close
d .... (hoặc tôi đoán chỉ những PrintWriter
nhu cầu được đóng lại vì đóng nó cũng nên đóng lại StringWriter
)
Đoạn mã sau cho phép bạn lấy toàn bộ stackTrace với String
định dạng mà không cần sử dụng các API như log4J hoặc thậm chí 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.
}
Đây là một phiên bản có thể sao chép trực tiếp vào mã:
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());
Hoặc, trong một khối bắt
} catch (Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
logger.info("Current stack trace is:\n" + sw.toString());
}
Throwable
được định nghĩa, phải không?
Arrays.toString(thrown.getStackTrace())
Là cách dễ nhất để chuyển đổi kết quả thành Chuỗi Tôi đang sử dụng điều này trong chương trình của mình để in theo dõi ngăn xếp
LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});
In dấu vết ngăn xếp thành a PrintStream
, sau đó chuyển đổi nó thành String
:
// ...
catch (Exception e)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(out));
String str = new String(out.toByteArray());
System.out.println(str);
}
In dấu vết ngăn xếp thành chuỗi
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);
}
}
}
Nó hữu ích khi bạn muốn in theo dõi ngăn xếp luồng hiện tại mà không cần tạo ra Throwable
- nhưng lưu ý rằng việc tạo mới Throwable
và theo dõi ngăn xếp từ đó thực sự nhanh hơn và rẻ hơn so với gọi Thread.getStackTrace
.
private String getCurrentStackTraceString() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
return Arrays.stream(stackTrace).map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
}
Việc bắn tỉa thông minh trong các bình luận đầu tiên rất thú vị, nhưng nó thực sự phụ thuộc vào những gì bạn đang cố gắng làm. Nếu bạn chưa có thư viện chính xác, thì 3 dòng mã (như trong câu trả lời của D. Classicalblewski) là hoàn hảo. OTOH, nếu bạn đã có thư viện apache.commons (vì hầu hết các dự án lớn sẽ có), thì câu trả lời của Amar ngắn hơn. OK, bạn có thể mất mười phút để lấy thư viện và cài đặt chính xác (ít hơn một nếu bạn biết bạn đang làm gì). Nhưng đồng hồ đang kêu, vì vậy bạn có thể không có thời gian rảnh rỗi. Jarek Przygódzki đã có một cảnh báo thú vị - "Nếu bạn không cần ngoại lệ lồng nhau".
Nhưng nếu tôi làm cần ngăn xếp dấu vết đầy đủ, lồng nhau và tất cả? Trong trường hợp đó, bí mật là sử dụng getFullStackTrace của apache.common (xem http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html # getFullStackTrace% 28java.lang. Có thể chia sẻ% 29 )
Nó đã cứu thịt xông khói của tôi. Cảm ơn, Amar, cho gợi ý!
Mã từ 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();
}
Sự khác biệt với các câu trả lời khác là nó sử dụng autoFlush
trên PrintWriter
.
Nếu không có java.io.*
nó có thể được thực hiện như thế này.
String trace = e.toString() + "\n";
for (StackTraceElement e1 : e.getStackTrace()) {
trace += "\t at " + e1.toString() + "\n";
}
Và sau đó trace
biến giữ dấu vết ngăn xếp của bạn. Đầu ra cũng giữ nguyên nhân ban đầu, đầu ra giống hệt vớiprintStackTrace()
Ví dụ, printStackTrace()
sản lượng:
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)
Các trace
chuỗi nắm giữ, khi in để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)
Phiên bản Scala
def stackTraceToString(e: Exception): String = {
import java.io.PrintWriter
val sw = new StringWriter()
e.printStackTrace(new PrintWriter(sw))
sw.toString
}
nếu bạn đang sử dụng Java 8, hãy thử điều này
Arrays.stream(e.getStackTrace())
.map(s->s.toString())
.collect(Collectors.joining("\n"));
bạn có thể tìm mã cho getStackTrace()
hàm được cung cấp bởi Throwable.java
:
public StackTraceElement[] getStackTrace() {
return getOurStackTrace().clone();
}
và cho StackTraceElement
, nó cung cấp toString()
như:
public String toString() {
return getClassName() + "." + methodName +
(isNativeMethod() ? "(Native Method)" :
(fileName != null && lineNumber >= 0 ?
"(" + fileName + ":" + lineNumber + ")" :
(fileName != null ? "("+fileName+")" : "(Unknown Source)")));
}
Vì vậy, chỉ cần tham gia StackTraceElement
với "\ n".
một ngoại lệ về câu trả lời của Gala cũng sẽ bao gồm các nguyên nhân cho ngoại lệ:
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;
}
Giải pháp là chuyển đổi stackTrace của mảng thành kiểu dữ liệu chuỗi . Xem ví dụ sau:
import java.util.Arrays;
try{
}catch(Exception ex){
String stack = Arrays.toString(ex.getStackTrace());
System.out.println("stack "+ stack);
}
Với API Java Stream 8, bạn có thể làm một cái gì đó như thế này:
Stream
.of(throwable.getStackTrace())
.map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
Nó sẽ lấy một loạt các phần tử theo dõi ngăn xếp, chuyển đổi chúng thành chuỗi và tham gia vào chuỗi đa dòng.
Oneliner của tôi để chuyển đổi dấu vết ngăn xếp thành chuỗi nhiều dòng kèm theo:
Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))
Dễ dàng chuyển đến logger "như hiện tại".
printStackTrace()
đây bạn sẽ mất: 1) Ngoại lệ đã bị ném; 2) Nguyên nhân và stacktrace của họ
printStackTrace()
không bao giờ là một phần của câu hỏi.
Nếu bạn không muốn sử dụng thư viện bên ngoài và bạn không phát triển cho Android , bạn có thể tạo phương thức 'tiện ích mở rộng' như thế này:
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();
}
Câu hỏi cũ, nhưng tôi chỉ muốn thêm trường hợp đặc biệt mà bạn không muốn in tất cả ngăn xếp , bằng cách xóa một số phần bạn không thực sự quan tâm, ngoại trừ các lớp hoặc gói nhất định.
Thay vì PrintWriter
sử dụng một 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);
Trường hợp SelectivePrintWriter
lớp được đưa ra bởi:
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);
}
}
}
Xin lưu ý rằng lớp này có thể dễ dàng được điều chỉnh để lọc ra theo Regex contains
hoặc các tiêu chí khác. Cũng lưu ý rằng nó phụ thuộc vào Throwable
chi tiết thực hiện (không có khả năng thay đổi, nhưng vẫn còn).
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);
}
}
}
Khi bạn chạy chương trình, đầu ra sẽ tương tự:
java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)
Cảnh báo: Điều này có thể hơi lạc đề, nhưng ồ ...;)
Tôi không biết lý do áp phích ban đầu là gì vì muốn theo dõi ngăn xếp dưới dạng chuỗi ở vị trí đầu tiên. Khi theo dõi ngăn xếp sẽ kết thúc trong một SLF4J / Logback LOG, nhưng không có ngoại lệ nào hoặc nên được ném ở đây những gì tôi làm:
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
}
Tôi thích nó bởi vì nó không yêu cầu một thư viện bên ngoài (trừ phần phụ trợ đăng nhập của bạn, tất nhiên sẽ luôn ở vị trí hầu hết thời gian).
Vài lựa chọn
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Sử dụng Google Guava lib
String stackTrace = Throwables.getStackTraceAsString ( myException ) ;
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace (Có thể ném)