จะส่ง stacktrace ไปยัง log4j ได้อย่างไร?


152

สมมติว่าคุณตรวจพบข้อยกเว้นและรับสิ่งต่อไปนี้ในเอาต์พุตมาตรฐาน (เช่นพูดคอนโซล) หากคุณทำe.printStackTrace () :

java.io.FileNotFoundException: so.txt
        at java.io.FileInputStream.<init>(FileInputStream.java)
        at ExTest.readMyFile(ExTest.java:19)
        at ExTest.main(ExTest.java:7)

ตอนนี้ฉันต้องการส่งสิ่งนี้แทนคนตัดไม้เช่น, พูด, log4j เพื่อรับสิ่งต่อไปนี้:

31947 [AWT-EventQueue-0] ERROR Java.io.FileNotFoundException: so.txt
32204 [AWT-EventQueue-0] ERROR    at java.io.FileInputStream.<init>(FileInputStream.java)
32235 [AWT-EventQueue-0] ERROR    at ExTest.readMyFile(ExTest.java:19)
32370 [AWT-EventQueue-0] ERROR    at ExTest.main(ExTest.java:7)

ฉันจะทำสิ่งนี้ได้อย่างไร

try {
   ...
} catch (Exception e) {
    final String s;
    ...  // <-- What goes here?
    log.error( s );
}

คำตอบ:


262

คุณส่งข้อยกเว้นไปยังตัวบันทึกโดยตรงเช่น

try {
   ...
} catch (Exception e) {
    log.error( "failed!", e );
}

มันขึ้นอยู่กับ log4j เพื่อสร้างการติดตามสแต็ก


32
คนตัดไม้ใช้วัตถุสำหรับการโต้แย้งครั้งแรกและจะ toString () มัน อย่างไรก็ตามอาร์กิวเมนต์ที่สองจะต้องเป็น Throwable และแสดงการติดตามสแต็ก
Peter Lawrey

1
ฉันไม่เคยรู้ว่าสิ่งใดที่จะเข้าสู่ String แรกฉันมักจะจบลงด้วยการทำlog.error(e.getLocalizedMessage(), e)ซ้ำซ้อนอย่างสมบูรณ์ มันจัดการ null สำหรับอาร์กิวเมนต์แรกหรือไม่
Mark Peters

5
@ Mark: พยายามที่จะให้ข้อความที่เกี่ยวข้องกับบริบทมากกว่าข้อความยกเว้นเช่นมันพยายามทำอะไรในเวลาจริง?
skaffman

2
@ Mark Peters ตัวอย่างที่ดีอาจบันทึกอาร์กิวเมนต์ไปยังเมธอดปัจจุบันเป็นข้อความหรือ - สำหรับข้อยกเว้น FileNotFound ชื่อเต็มของพา ธ ที่พยายามจะเปิด อะไรก็ตามที่สามารถช่วยคุณค้นหาสิ่งที่ผิด - เพียงแค่คิดว่าคุณไม่สามารถแก้ไขข้อบกพร่องของสถานการณ์ได้
Thorbjørn Ravn Andersen

1
@skaffman: ที่จริงผมใช้log4j-1.2.8.jarและฉันต้องการที่จะพิมพ์ทั้งหมดstackTraceในแฟ้มบันทึกของฉันดังนั้นฉันพยายามเหมือนข้างต้นที่คุณกล่าวถึง nullPointerExceptionแต่จะพิมพ์บนแฟ้มบันทึกของฉันเท่านั้น ฉันใช้รหัสของฉันe.printStackTrace()มันพิมพ์ร่องรอยทั้งหมด ทำไม Kolavery นี้
Yubaraj

9

หากคุณต้องการบันทึก stacktrace โดยไม่ต้องมีข้อยกเว้นให้ทำดังนี้

String message = "";

for(StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {                         
    message = message + System.lineSeparator() + stackTraceElement.toString();
}   
log.warn("Something weird happened. I will print the the complete stacktrace even if we have no exception just to help you find the cause" + message);

3
+1 สำหรับ System.lineSeparator () สิ่งนี้ช่วยให้ฉันพิมพ์ stacktrace ซึ่งฉันได้รับเป็นการตอบสนองจากบริการระยะไกล
Stephanie

1
สิ่งที่ฉันค้นหา แต่คุณควรใช้ StringBuilder ที่นี่
Xerus

9

ExceptionUtils.getStackTraceนอกจากนี้คุณยังสามารถได้รับการกองติดตามเป็นสตริงผ่าน

ดู: ExceptionUtils.java

ฉันใช้เพื่อlog.debugการlog.errorเรียบง่ายเท่านั้น


4

เพียงเพราะมันเกิดขึ้นกับฉันและจะมีประโยชน์ ถ้าคุณทำเช่นนี้

try {
   ...
} catch (Exception e) {
    log.error( "failed! {}", e );
}

คุณจะได้รับส่วนหัวของข้อยกเว้นไม่ใช่สแต็กสแต็กทั้งหมด เพราะคนตัดไม้จะคิดว่าคุณกำลังผ่านสตริง ทำโดยไม่ต้อง{}เป็น skaffman กล่าว


1
แน่นอนคุณจะได้รับการติดตามสแต็กทั้งหมดที่นี่ แต่ {} จะพิมพ์คำต่อคำด้วย (ไม่มีการทดแทนใด ๆ )?
k1eran

1
ไม่ต้องแน่ใจว่าเพื่อนของฉัน! มันไม่ได้ผลสำหรับฉันฉันได้รับแค่ส่วนหัว มันอาจขึ้นอยู่กับรุ่นของ log4j แม้ว่า
iberbeu

@iberbeu ถูกต้องเพราะThrowable.toString()ไม่ส่งคืนสแต็กสแต็ก (สมมติว่าคุณกำลังใช้ตัวบันทึกที่รู้ว่าจะทำอย่างไรกับ '{}')

4

คำตอบจาก skaffman เป็นคำตอบที่ถูกต้องแน่นอน ทุกวิธีการตัดไม้เช่นerror(), warn(), info(), debug()ใช้ Throwable เป็นพารามิเตอร์ที่สอง:

try {
...
 } catch (Exception e) {
logger.error("error: ", e);
}

อย่างไรก็ตามคุณสามารถแยก stacktrace เป็น String ได้เช่นกัน บางครั้งมันอาจมีประโยชน์ถ้าคุณต้องการใช้ประโยชน์จากการจัดรูปแบบฟีเจอร์โดยใช้ตัวยึด "{}" - ดูวิธีการvoid info(String var1, Object... var2);ในกรณีนี้บอกว่าคุณมี stacktrace เป็น String คุณสามารถทำสิ่งนี้ได้จริง:

try {
...
 } catch (Exception e) {
String stacktrace = TextUtils.getStacktrace(e);
logger.error("error occurred for usename {} and group {}, details: {}",username, group, stacktrace);
}

สิ่งนี้จะพิมพ์ข้อความที่กำหนดไว้แล้วและ stacktrace ในตอนท้ายเหมือนกับวิธีการ: logger.error("error: ", e);

จริง ๆ แล้วฉันเขียนไลบรารีโอเพนซอร์สที่มียูทิลิตี้สำหรับการแยกสแต็คเทรซเป็นสตริงพร้อมตัวเลือกในการกรองสัญญาณรบกวนออกจากสแต็คเทรซอย่างชาญฉลาด นั่นคือถ้าคุณระบุคำนำหน้าแพ็คเกจที่คุณสนใจในสแต็คสแต็คที่แยกของคุณจะถูกกรองออกจากส่วนที่ไม่เกี่ยวข้องและทำให้คุณได้รับข้อมูลที่ถูกต้องมาก นี่คือลิงค์ไปยังบทความที่อธิบายว่าห้องสมุดมีสาธารณูปโภคใดและจะรับได้ที่ไหน (ทั้งในฐานะสิ่งประดิษฐ์ maven และแหล่ง git) และวิธีการใช้งานเช่นกัน ไลบรารี Java แบบโอเพนซอร์สพร้อมการกรองแบบสแต็กการติดตามการแยกสตริงตัวแปลง Unicode แบบเงียบและการเปรียบเทียบรุ่น ดูที่ย่อหน้า " ตัวกรองสัญญาณรบกวนแบบสแต็คเทรซ "


1
คำตอบที่ถูกฝังอยู่ แต่ดี
เพน

ขอบคุณ @pnene ฉันขอขอบคุณการตอบรับที่ดี
Michael Gantman

2

คำตอบนี้อาจไม่เกี่ยวข้องกับคำถามที่ถาม แต่เกี่ยวข้องกับชื่อของคำถาม

public class ThrowableTest {

    public static void main(String[] args) {

        Throwable createdBy = new Throwable("Created at main()");
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintWriter pw = new PrintWriter(os);
        createdBy.printStackTrace(pw);
        try {
            pw.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.debug(os.toString());
    }
}

หรือ

public static String getStackTrace (Throwable t)
{
    StringWriter stringWriter = new StringWriter();
    PrintWriter  printWriter  = new PrintWriter(stringWriter);
    t.printStackTrace(printWriter);
    printWriter.close();    //surprise no IO exception here
    try {
        stringWriter.close();
    }
    catch (IOException e) {
    }
    return stringWriter.toString();
}

หรือ

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for(StackTraceElement stackTrace: stackTraceElements){
    logger.debug(stackTrace.getClassName()+ "  "+ stackTrace.getMethodName()+" "+stackTrace.getLineNumber());
}

1

ใน Log4j 2 คุณสามารถใช้Logger.catching ()เพื่อบันทึก stacktrace จากข้อยกเว้นที่ตรวจพบ

    try {
        String msg = messages[messages.length];
        logger.error("An exception should have been thrown");
    } catch (Exception ex) {
        logger.catching(ex);
    }

0

นี่จะเป็นข้อผิดพลาด log4j ที่ดี / การบันทึกข้อยกเว้น - อ่านได้โดย splunk / การบันทึกอื่น ๆ / การตรวจสอบ s / w ทุกอย่างเป็นรูปแบบของคู่คีย์ - ค่า log4j จะได้รับ stack trace จาก Exception obje

    try {
          ---
          ---
    } catch (Exception e) {
        log.error("api_name={} method={} _message=\"error description.\" msg={}", 
                  new Object[]{"api_name", "method_name", e.getMessage(), e});
    }


-1

คุณสามารถใช้รหัสร้อง:

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class LogWriterUtility {
    Logger log;

    public LogWriterUtility(Class<?> clazz) {
        log = LogManager.getLogger(clazz);
    }

public void errorWithAnalysis( Exception exception) {

        String message="No Message on error";
        StackTraceElement[] stackTrace = exception.getStackTrace();
        if(stackTrace!=null && stackTrace.length>0) {
            message="";
            for (StackTraceElement e : stackTrace) {
                message += "\n" + e.toString();
            }
        }
        log.error(message);


    }

}

ที่นี่คุณสามารถโทร: LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

มันจะพิมพ์ stackTrace ลงในบันทึกของคุณ


-2

สร้างสิ่งนี้class:

public class StdOutErrLog {

private static final Logger logger = Logger.getLogger(StdOutErrLog.class);

public static void tieSystemOutAndErrToLog() {
    System.setOut(createLoggingProxy(System.out));
    System.setErr(createLoggingProxy(System.err));
}

public static PrintStream createLoggingProxy(final PrintStream realPrintStream) {
    return new PrintStream(realPrintStream) {
        public void print(final String string) {
            logger.info(string);
        }
        public void println(final String string) {
            logger.info(string);
        }
    };
}
}

เรียกสิ่งนี้ในรหัสของคุณ

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