Bagaimana cara mengirim stacktrace ke log4j?


152

Katakanlah Anda menangkap pengecualian dan dapatkan yang berikut pada output standar (seperti, katakanlah, konsol) jika Anda melakukan 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)

Sekarang saya ingin mengirim ini sebagai ganti ke logger seperti, katakanlah, log4j untuk mendapatkan yang berikut ini:

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)

Bagaimana saya bisa melakukan ini?

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

Jawaban:


262

Anda mengirimkan pengecualian langsung ke logger, mis

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

Terserah log4j untuk membuat jejak stack.


32
Logger mengambil objek untuk argumen pertamanya dan akan toString () itu. Namun argumen kedua harus Throwable dan menampilkan jejak stack.
Peter Lawrey

1
Saya tidak pernah tahu apa yang harus dimasukkan ke dalam String pertama, biasanya saya hanya melakukan log.error(e.getLocalizedMessage(), e)yang benar-benar berlebihan. Apakah itu menangani nol untuk argumen pertama?
Mark Peters

5
@ Mark: Cobalah untuk memberikan pesan yang lebih sesuai dengan konteks daripada pesan pengecualian, misalnya apa yang sebenarnya ingin dilakukan pada saat itu?
skaffman

2
@ Mark Peters, Contoh yang baik bisa mencatat argumen ke metode saat ini sebagai pesan, atau - untuk pengecualian FileNotFound nama lengkap jalur yang dicoba dibuka. Apa pun yang dapat membantu Anda mengetahui apa yang salah - anggap saja Anda tidak dapat men-debug situasi.
Thorbjørn Ravn Andersen

1
@skaffman: Sebenarnya saya menggunakan log4j-1.2.8.jardan saya ingin mencetak semua stackTracepada file log saya jadi saya mencoba seperti yang Anda sebutkan di atas tetapi sedang mencetak pada file log saya saja nullPointerException. Saya digunakan pada kode saya e.printStackTrace()untuk mencetak semua jejak. Kenapa Kolavery ini?
Yubaraj

9

Jika Anda ingin mencatat stacktrace tanpa melibatkan pengecualian lakukan saja ini:

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 untuk System.lineSeparator (), ini membantu saya untuk mencetak stacktrace yang saya dapatkan sebagai respons dari layanan jarak jauh
Stephanie

1
apa yang saya cari, tetapi Anda harus menggunakan StringBuilder di sini
Xerus

9

Anda juga bisa mendapatkan jejak stack sebagai string melalui ExceptionUtils.getStackTrace.

Lihat: ExceptionUtils.java

Saya menggunakannya hanya untuk log.debug, agar tetap log.errorsederhana.


4

Hanya karena itu terjadi pada saya dan dapat bermanfaat. Jika kamu melakukan ini

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

Anda akan mendapatkan header pengecualian dan bukan seluruh stacktrace. Karena logger akan berpikir bahwa Anda melewatkan sebuah String. Lakukan tanpa {}seperti yang dikatakan skaffman


1
Tentunya Anda akan mendapatkan jejak seluruh tumpukan di sini, namun {} juga akan dicetak kata demi kata (tanpa substitusi)?
k1eran

1
jangan terlalu yakin teman saya! Itu tidak berhasil bagi saya, saya hanya mendapatkan header. Itu bisa tergantung pada versi log4j
iberbeu

@ iberbeu benar karena Throwable.toString()tidak mengembalikan stacktrace. (Dengan asumsi Anda menggunakan logger yang tahu apa yang harus dilakukan dengan '{}'.)

4

Jawaban dari skaffman jelas merupakan jawaban yang benar. Semua metode logger seperti error(), warn(), info(), debug()mengambil Throwable sebagai parameter kedua:

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

Namun, Anda dapat mengekstrak stacktrace sebagai String juga. Terkadang ini bisa berguna jika Anda ingin memanfaatkan fitur pemformatan menggunakan placeholder "{}" - lihat metode void info(String var1, Object... var2);Dalam kasus ini katakan Anda memiliki stacktrace sebagai String, maka Anda sebenarnya dapat melakukan sesuatu seperti ini:

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

Ini akan mencetak pesan parametrized dan stacktrace di akhir dengan cara yang sama seperti untuk metode: logger.error("error: ", e);

Saya benar-benar menulis perpustakaan open source yang memiliki Utilitas untuk ekstraksi stacktrace sebagai String dengan opsi untuk secara cerdas menyaring beberapa kebisingan dari stacktrace. Yaitu jika Anda menentukan awalan paket yang Anda minati dengan stacktrace yang Anda ekstrak akan disaring dari beberapa bagian yang tidak relevan dan memberi Anda info yang sangat rumit. Berikut adalah tautan ke artikel yang menjelaskan utilitas apa yang dimiliki perpustakaan dan di mana mendapatkannya (baik sebagai artefak pakar dan sumber git) dan bagaimana menggunakannya juga. Pustaka Java Open Source dengan pemfilteran stack trace, Silent String parsing Unicode converter dan perbandingan versi Lihat paragraf " Stacktrace noise filter "


1
Jawaban yang terkubur tapi bagus.
bayar

Terima kasih, @payne. Saya menghargai umpan balik yang bagus
Michael Gantman

2

Jawaban ini mungkin tidak terkait dengan pertanyaan yang diajukan tetapi terkait dengan judul pertanyaan.

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

ATAU

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

ATAU

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

1

Di Log4j 2, Anda bisa menggunakan Logger.catching () untuk mencatat stacktrace dari pengecualian yang tertangkap.

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

0

ini akan menjadi log4j error / pengecualian logging - dapat dibaca oleh splunk / logging / monitoring s / w lainnya. semuanya adalah bentuk pasangan kunci-nilai. log4j akan mendapatkan jejak stack dari Exception obje

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

0
Try this:

catch (Throwable t) {
    logger.error("any message" + t);
    StackTraceElement[] s = t.getStackTrace();
    for(StackTraceElement e : s){
        logger.error("\tat " + e);
    }   
}

-1

Anda dapat menggunakan kode di bawah ini:

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


    }

}

Di sini Anda bisa menelepon: LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

Ini akan mencetak stackTrace ke log Anda.


-2

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

Sebut ini dalam kode Anda

StdOutErrLog.tieSystemOutAndErrToLog();
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.