ฉันจะแปลงการติดตามสแต็กเป็นสตริงได้อย่างไร


1502

เป็นวิธีที่ง่ายที่สุดในการแปลงผลลัพธ์ของThrowable.getStackTrace()การเป็นสายอักขระที่แสดงให้เห็นถึง stacktrace อะไร


6
เนื่องจากคำตอบของ jqno ใช้วิธี Throwable.getStackTrace () ที่คุณระบุไว้ในคำถามของคุณในขณะที่ Brian ไม่ได้ เขาใช้ Throwable.printStackTrace () แทน
Stijn de Witt

10
เกือบทุกโครงการ Java ควรรวม Apache commons-lang มันมีวิธีอำนวยความสะดวกมากมายในการดำเนินการตามความต้องการด้านการพัฒนา
รัสเซลซิลวา

20
@StijndeWitt โค้ดสามบรรทัดนั้นเกือบจะต้องแยกจากที่ที่คุณเรียกว่า เนื่องจากคุณไม่ทราบว่าจะนำไปไว้ที่ไหนพวกเขาจะเข้าสู่กล่องเครื่องมืออรรถประโยชน์พร้อมกับตัวอย่างที่เป็นประโยชน์อื่น ๆ ทั้งหมด บิงโก! คุณเพิ่งสร้างใหม่ฝรั่ง / คอมมอนส์ - lang / อะไรก็ได้ ... ไม่ค่อยดี นำเข้าไลบรารียูทิลิตี้ที่เหมาะสมแทนและบันทึกการปรับโครงสร้างล้อ สัญลักษณ์ที่แท้จริงของสามเณรคือการคิดว่าคุณสามารถทำงานได้ดีกว่านักเขียนห้องสมุด
Andrew Spencer

6
1. Guava มี - Throwables.getStackTraceAsString (e) 2. Apache Commons Lang - ExceptionUtils.getFullStackTrace 3. เขียนวิธีการกำหนดเองของเรา
user2323036

8
@AndrewSpencer ฉันไม่เข้าใจว่าทำไมพวกคุณพยายามอย่างหนักที่จะทุบตี StijndeWitt เพราะต้องการทำสิ่งนี้ด้วยตัวอย่างเล็ก ๆ มีอันตรายไม่มากนักในการเขียนวิธีการอรรถประโยชน์เล็ก ๆ (ฉันไม่เห็นว่าเป็น "SHEER ARROGANCE โอ้ nooooo !! เขาคิดว่าเขาดีกว่า Apache !!") มีโครงการมากมายโดยเฉพาะในภาษาที่ไม่ใช่ Java JVM ที่ไม่ต้องการรวม Guava หรือ Commons Lang เพียงเพื่อบันทึกสแต็ค ฉันเขียนไลบรารี Scala & Clojure และแน่นอนว่าจะไม่ทำให้ Apache Commons Lang พึ่งพาการถ่ายทอดผ่านวิธีการเพียงวิธีเดียว
jm0

คำตอบ:


1039

หนึ่งสามารถใช้วิธีการต่อไปนี้เพื่อแปลงกองติดตามไปException Stringคลาสนี้มีอยู่ในApache Commons-lang ซึ่งเป็นไลบรารี่ทั่วไปที่มีโอเพ่นซอร์สยอดนิยมมากมาย

org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)


88
@Stijn - เป็นธรรม (ฉันเขียนคำตอบที่ได้รับคะแนนสูงสุดในปัจจุบันด้านล่าง) มันคุ้มค่าที่จะดูคอมมอนส์ - lang สำหรับการใช้งานอื่น ๆ อีกมากมาย
Brian Agnew

54
@ StijndeWitt คอมมอนส์ Lang เป็นเรื่องธรรมดา มันมีอยู่แล้วในโครงการ / งานส่วนใหญ่ของฉัน
WhyNotHugo

16
@Hugo ขอบคุณจะใช้ StringWriter เพื่อหลีกเลี่ยงการเพิ่มห้องสมุดใหม่ - ปรากฎว่ามันขึ้นอยู่กับการพึ่งพา 3 จากการอ้างอิงของฉัน ดังนั้นสำหรับส่วนที่เหลือให้ตรวจสอบว่าคุณมีอยู่แล้ว
Nathanial

33
@MartinAsenov - ทำตามตรรกะของคุณคุณไม่เคยใช้ห้องสมุดแบบนี้มาก่อนหรือเปล่า? คุณจะไม่ใช้มันถ้าคุณไม่ได้ใช้มันอยู่แล้ว?
Brian Agnew

16
FYI, org.apache.commons.lang3.exception.ExceptionUtilsแพคเกจที่มีการเปลี่ยนแปลงและชั้นอยู่ในขณะนี้ได้ที่:
schmmd

2201

ใช้Throwable.printStackTrace(PrintWriter pw)เพื่อส่งการติดตามสแต็กไปยังตัวเขียนที่เหมาะสม

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

505
หากคุณไม่ต้องการรวมไลบรารีภายนอกสำหรับสิ่งที่เล็กและเรียบง่ายเช่นนี้ให้ใช้คำตอบนี้
Stijn de Witt

8
วิธีนี้จะตัดการติดตามสแต็กเหมือนกับ printStackTrace () ข้อยกเว้นทั้งหมดในสแต็กสามารถมองเห็นได้ แต่สำหรับแต่ละข้อยกเว้นสแต็กอาจถูกตัดออก ทุกคนที่ต้องการการติดตามทั้งหมดควรพิจารณาสิ่งนี้
Laila Agaev

5
สิ่งนี้ตามที่ปรากฎออกมามันค่อนข้างเหมือนกับที่ ExceptionUtils.getStackTrace () ของ apache ใช้ เกือบจะถึงจดหมายจริง
ticktock

6
@BrianAgnew คุณไม่ควรปิดStringWriterและPrintWriter?
มูฮัมหมัด Gelbana

13
@BrianAgnew ขอบคุณสำหรับการตอบกลับ มันทำให้ฉันอยากรู้อยากเห็นและนี่คือสิ่งที่ฉันพบ: stackoverflow.com/questions/14542535/ …
Muhammad Gelbana

459

สิ่งนี้น่าจะใช้ได้:

StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();

69
กระชับในบริบทของจาวาเป็นอย่างมากตลอดเวลา นั่นprintStackTraceก็ควรจะกลับสตริงออกจากการตัดสินใจว่าพิมพ์หรือไม่ที่จะใช้ :)
Dmitry

35
printStackTrace การพิมพ์ในคอนโซลเป็นที่ยอมรับ แต่อย่างน้อย getStackTrace ที่ส่งคืนเป็นสตริงควรพร้อมใช้งานตามค่าเริ่มต้น
Mateus Viccari

5
ส่วนใดของสิ่งนี้กระชับ คุณต้องสร้างวัตถุ 2 ชิ้นที่มีอยู่โดยไม่มีวัตถุประสงค์อื่นนอกจากใส่สแต็กติดตามลงในสตริง
ArtOfWarfare

7
@dmitry วิธีการที่เรียกว่าprintXXX()ควรพิมพ์ XXX
user207421

2
@ Greg จริง ๆ แล้วที่ไม่ได้พูดเล่นก็ต้องอ่านสิ่งที่เขาพูด
แอนดรู

224

หากคุณกำลังพัฒนาสำหรับ Android วิธีที่ง่ายกว่าคือใช้สิ่งนี้:

import android.util.Log;

String stackTrace = Log.getStackTraceString(exception); 

รูปแบบเหมือนกับ getStacktrace เช่น

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)

2
ขอบคุณ ในกรณีนี้วันที่และแท็กจะไม่ถูกเขียนในทุกแถวเหมือนใน printStackTrace ()
CoolMind

1
จริง ๆ แล้ว Log.getStackTraceString ในแกนนั้นใช้ StringWriter และ Printwriter ดังกล่าวข้างต้น (D. Wroblewski's)
MikeL

2
วิธีที่ง่ายที่สุดในการพิมพ์ในบันทึกของ Android คือ: Log.e("TAG", "My message", new Throwable());
Erick M. Sprengel


113

คำเตือน: ไม่รวมถึงสาเหตุ (ซึ่งมักจะเป็นบิตที่มีประโยชน์!)

public String stackTraceToString(Throwable e) {
    StringBuilder sb = new StringBuilder();
    for (StackTraceElement element : e.getStackTrace()) {
        sb.append(element.toString());
        sb.append("\n");
    }
    return sb.toString();
}

1
ฉันจะไปกับส่วนขยายของวิธีการนี้ถ้าคุณต้องการตัดแต่งร่องรอยเช่นผ่านพารามิเตอร์ maxLines และเพียงเพิ่มบรรทัดจำนวนมากที่ติดตาม
Rich ผู้ขาย

วงเล็บหลัง e.getStackTrace หายไป String สาธารณะแบบคงที่ stackTraceToString (ข้อยกเว้น e) {StringBuilder sb = new StringBuilder (); สำหรับองค์ประกอบ (StackTraceElement: e.getStackTrace ()) {sb.append (element.toString ()); sb.append ("<br />"); } คืน sb.toString (); }
rlc

2
ไม่แน่ใจ แต่ฉันคิดว่านี่จะไม่พิมพ์การติดตามสแต็กของข้อผิดพลาดสาเหตุหลัก
apoorv020

7
ไม่ว่าคุณจะทำอะไร มันเกิดขึ้นกับฉันหลายครั้งหลายคราที่ฉันดูร่องรอยการแตกในบันทึก GlassFish ที่มีส่วนที่เป็นประโยชน์ถูกตัดออกไป
cayhorstmann

ใช้String.format("%n")หรืออะไรที่คล้ายกันแทน"\n"การทำให้ DOS lamers มีความสุข
ceving

89

สำหรับฉันวิธีที่สะอาดและง่ายที่สุดคือ:

import java.util.Arrays;
Arrays.toString(e.getStackTrace());

37
รหัสสะอาด แต่ผลลัพธ์ไม่ได้ คุณต้องทำ. แทนที่ทั้งหมด (",", "\ n") ในที่สุด อย่างไรก็ตามคุณสูญเสียการเยื้องที่ printStackTrace เสนอ
โกรธ

4
สิ่งนี้มีประโยชน์เมื่อคุณบันทึกการติดตามในบรรทัดเดียว
webjockey

28
public static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    return sw.toString();
}

1
สวัสดีฉันอยากจะชี้ให้เห็นว่าส่วนความเห็นของคำตอบที่อ้างถึงชี้ให้เห็นว่าStringWriterและPrintWriterวัตถุควรจะเป็นclosed .... (หรือฉันเดาPrintWriterว่าความต้องการที่จะปิดตั้งแต่ปิดก็ควรปิดStringWriterเช่นกัน)
Eric

8
โดยแรงบันดาลใจหมายถึงคุณคัดลอก? คุณจะใส่ไว้ในวิธีการ ... อ่านคำตอบที่นี่เป็นเหมือนการดู "วัน Groundhog"
Murmel

26

รหัสต่อไปนี้ช่วยให้คุณได้รับทั้ง stackTrace ด้วยStringรูปแบบโดยไม่ต้องใช้ API เช่น log4J หรือแม้กระทั่ง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.
}

1
คุณคิดว่ามันค่อนข้างใหญ่ใช่ไหม? ในกรอบการบันทึกโครงการขนาดที่เหมาะสมใด ๆ เป็นสิ่งจำเป็นดังนั้นทำไมรำคาญ
mzzzzb

อันนี้ไม่ได้ให้ข้อความข้อผิดพลาดในการเริ่มต้น สามารถเพิ่มแม้ว่า
kommradHomer

คุณอาจต้องการใช้ StringBuffer แทนการต่อข้อมูลอย่างง่าย
dedda1994

สิ่งนี้มีประโยชน์เมื่อคุณไม่ได้รับอนุญาตให้บันทึกข้อความเพื่อเหตุผลด้านความเป็นส่วนตัว
A1m

โปรดระวังด้วยว่าโซลูชันนี้จะไม่บันทึกสาเหตุภายใน
A1m

19

นี่คือรุ่นที่คัดลอกวางได้โดยตรงในรหัส:

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

หรือในการบล็อกการจับ

} catch (Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    logger.info("Current stack trace is:\n" + sw.toString());
}

สิ่งนี้จะดำเนินต่อไปนอกเหนือขอบเขตของฟังก์ชันปัจจุบันเช่น ที่Throwableถูกกำหนดไว้ถูกต้อง?
n611x007

16
Arrays.toString(thrown.getStackTrace())

เป็นวิธีที่ง่ายที่สุดในการแปลงผลลัพธ์เป็น String I ที่ใช้ในโปรแกรมของฉันเพื่อพิมพ์ stack trace

LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});

ทำงานให้ฉันไม่มีอะไรที่ดูถูกตัด! ง่ายกว่าคำตอบอื่น ๆ โดยไม่ต้องมีห้องสมุดภายนอกคำตอบที่ยอดเยี่ยม!
Shaung Cheng

16

พิมพ์ stack trace เป็น a PrintStreamจากนั้นแปลงเป็น a String:

// ...

catch (Exception e)
{
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    e.printStackTrace(new PrintStream(out));
    String str = new String(out.toByteArray());

    System.out.println(str);
}

1
นี่เป็นคำตอบที่ตรงที่สุด
DaSqy Stc

11

การพิมพ์การติดตามสแต็กเป็นสตริง

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

มันมีประโยชน์เมื่อคุณต้องการพิมพ์ร่องรอยด้ายสแต็คในปัจจุบันโดยไม่ต้องสร้างอินสแตนซ์Throwable- แต่ทราบว่าการสร้างใหม่และได้รับการติดตามสแต็คจากที่นั่นเป็นจริงได้เร็วขึ้นและมีราคาถูกกว่าการโทรThrowableThread.getStackTrace


11

Kotlin

การขยายคลาส Throwable จะทำให้คุณมีคุณสมบัติ String error.stackTraceString:

val Throwable.stackTraceString: String
  get() {
    val sw = StringWriter()
    val pw = PrintWriter(sw)
    this.printStackTrace(pw)
    return sw.toString()
  }

10
private String getCurrentStackTraceString() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    return Arrays.stream(stackTrace).map(StackTraceElement::toString)
            .collect(Collectors.joining("\n"));
}

1
ขอบคุณ eddyrkokr! มันใช้งานได้สมบูรณ์แบบสำหรับทุกส่วนของฉัน ฉันเพิ่งเพิ่มมันลงในคลาส TestNG และมันรวบรวมสแต็คตระเวนหนึ่งต่อหนึ่งจากการทดสอบทั้งหมดของฉัน!
Krzysztof Walczewski

9

ความฉลาดในการแสดงความคิดเห็นชุดแรกนั้นสนุกมาก แต่มันก็ขึ้นอยู่กับสิ่งที่คุณพยายามทำ หากคุณยังไม่มีไลบรารี่ที่ถูกต้องรหัส 3 บรรทัด (เช่นเดียวกับคำตอบของ D. Wroblewski) นั้นสมบูรณ์แบบ OTOH ถ้าคุณมีห้องสมุด apache.commons อยู่แล้ว (ตามโครงการขนาดใหญ่ส่วนใหญ่) คำตอบของ Amar ก็จะสั้นลง ตกลงอาจใช้เวลาสิบนาทีในการรับห้องสมุดและติดตั้งอย่างถูกต้อง (น้อยกว่าหนึ่งถ้าคุณรู้ว่าคุณกำลังทำอะไรอยู่) แต่นาฬิกากำลังฟ้องดังนั้นคุณอาจไม่มีเวลาว่าง Jarek Przygódzkiมีข้อแม้ที่น่าสนใจ - "ถ้าคุณไม่ต้องการข้อยกเว้นซ้อน"

แต่ถ้าฉันไม่จำเป็นต้องมีร่องรอยสแต็คเต็มรูปแบบซ้อนกันและทั้งหมดหรือไม่ ในกรณีดังกล่าวความลับคือการใช้ getFullStackTrace ของ apache.com (ดูที่http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html # getFullStackTrace% 28java.lang.Throwable 29% )

มันช่วยเบคอนของฉัน ขอบคุณ Amar สำหรับคำใบ้!


9

รหัสจาก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();
}

แตกต่างกับคำตอบอื่น ๆ ที่จะใช้ ในautoFlushPrintWriter


8

ไม่java.io.*สามารถทำได้เช่นนี้

String trace = e.toString() + "\n";                     

for (StackTraceElement e1 : e.getStackTrace()) {
    trace += "\t at " + e1.toString() + "\n";
}   

แล้วtraceตัวแปรก็เก็บสแต็กของคุณไว้ เอาท์พุทยังถือสาเหตุเริ่มต้นเอาท์พุทเหมือนกันprintStackTrace()

ตัวอย่างprintStackTrace()อัตราผลตอบแทน:

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)

traceString ถือเมื่อพิมพ์ไป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)

5

รุ่นสกาล่า

def stackTraceToString(e: Exception): String = {
  import java.io.PrintWriter
  val sw = new StringWriter()
  e.printStackTrace(new PrintWriter(sw))
  sw.toString
}

5

หากคุณใช้ Java 8 ให้ลองสิ่งนี้

Arrays.stream(e.getStackTrace())
                .map(s->s.toString())
                .collect(Collectors.joining("\n"));

คุณสามารถค้นหารหัสสำหรับgetStackTrace()ฟังก์ชั่นที่จัดทำโดยThrowable.javaเป็น:

public StackTraceElement[] getStackTrace() {
    return getOurStackTrace().clone();
}

และสำหรับStackTraceElementผู้ให้บริการมันtoString()เป็น:

public String toString() {
    return getClassName() + "." + methodName +
        (isNativeMethod() ? "(Native Method)" :
         (fileName != null && lineNumber >= 0 ?
          "(" + fileName + ":" + lineNumber + ")" :
          (fileName != null ?  "("+fileName+")" : "(Unknown Source)")));
}

ดังนั้นเพียงแค่เข้าร่วมStackTraceElementกับ "\ n"


โซลูชันนี้ไม่เคารพแท็บการติดตามสแต็กการเยื้องมิฉะนั้นจะใช้งานได้ดี!
krizajb

4

exapansion ในคำตอบของ Gala ที่จะรวมถึงสาเหตุของข้อยกเว้น:

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

4

วิธีแก้ไขคือการแปลง stackTrace ของอาเรย์เป็นประเภทข้อมูลสตริง ดูตัวอย่างต่อไปนี้:

import java.util.Arrays;

try{

}catch(Exception ex){
    String stack = Arrays.toString(ex.getStackTrace());
    System.out.println("stack "+ stack);
}

4

ด้วย Java 8 Stream APIคุณสามารถทำสิ่งนี้:

Stream
    .of(throwable.getStackTrace())
    .map(StackTraceElement::toString)
    .collect(Collectors.joining("\n"));

มันจะใช้อาร์เรย์ขององค์ประกอบการติดตามสแต็คแปลงเป็นสตริงและเข้าร่วมเป็นสตริงหลายบรรทัด


2
โซลูชันนี้กำลังลบข้อความและไม่สนใจการติดตามของผู้ปกครองทั้งหมด
judovana

3

Oneliner ของฉันเพื่อแปลงการติดตามสแต็กเป็นสตริงที่มีหลายบรรทัด:

Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))

ง่ายต่อการส่งผ่านไปยังคนตัดไม้ "ตามที่เป็น"


คุณได้สิ่งที่แตกต่างจากที่printStackTrace()นี่คุณจะหลวม: 1) ข้อยกเว้นที่ถูกโยน; 2) สาเหตุและ stacktrace ของพวกเขา
valijon

ความแตกต่างค่อนข้างคาดหวังตั้งแต่การแปลงของprintStackTrace()ไม่เคยเป็นส่วนหนึ่งของคำถาม
Andrey Lebedenko

2

หากคุณไม่ต้องการใช้ห้องสมุดภายนอกและคุณไม่ได้พัฒนาสำหรับ Androidคุณสามารถสร้างวิธีการ'ขยาย'แบบนี้:

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

2

คำถามเก่า แต่ฉันต้องการเพิ่มเคสพิเศษที่คุณไม่ต้องการพิมพ์สแต็กทั้งหมดกทั้งหมดโดยการลบบางส่วนที่คุณไม่สนใจจริง ๆ ยกเว้นคลาสหรือแพ็คเกจที่แน่นอน

แทนที่จะPrintWriterใช้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);

ในกรณีที่SelectivePrintWriterระดับจะได้รับโดย:

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

โปรดทราบว่าคลาสนี้สามารถปรับเปลี่ยนได้ง่ายเพื่อกรองโดย Regex containsหรือเกณฑ์อื่น ๆ โปรดทราบว่าขึ้นอยู่กับThrowableรายละเอียดการใช้งาน (ไม่น่าจะเปลี่ยนแปลง แต่ยังคงอยู่)


1
ใช่มันใช้งานได้ดีและจริง ๆ แล้วเป็นแนวคิดที่มีประโยชน์
gil.fernandes

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

เมื่อคุณรันโปรแกรมผลลัพธ์จะคล้ายกัน:

java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)

1

ฉันสงสัยว่าทำไมไม่มีใครพูดถึง ExceptionUtils.getStackFrames(exception)

สำหรับฉันมันเป็นวิธีที่สะดวกที่สุดในการถ่ายโอน stacktrace ด้วยสาเหตุทั้งหมดจนถึงที่สุด:

String.join("\n", ExceptionUtils.getStackFrames(exception));

0

คำเตือน: นี่อาจจะเป็นหัวข้อเล็กน้อย แต่ก็ดี ... ;)

ฉันไม่ทราบว่าเหตุผลดั้งเดิมของผู้โพสต์คือต้องการให้ร่องรอยสแต็กเป็นสตริงในตอนแรก เมื่อการติดตามสแต็คควรจบลงใน SLF4J / Logback LOG แต่ไม่มีข้อยกเว้นหรือควรถูกโยนนี่คือสิ่งที่ฉันทำ:

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
}

ฉันชอบเพราะมันไม่จำเป็นต้องมีห้องสมุดภายนอก (นอกเหนือจากแบ็กเอนด์เข้าสู่ระบบของคุณซึ่งจะใช้เวลาส่วนใหญ่อยู่แล้วแน่นอน)


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.