Wie sende ich einen Stacktrace an log4j?


152

Angenommen, Sie fangen eine Ausnahme ab und erhalten Folgendes für die Standardausgabe (z. B. die Konsole), wenn Sie eine e.printStackTrace () ausführen :

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

Jetzt möchte ich dies stattdessen an einen Logger wie beispielsweise log4j senden, um Folgendes zu erhalten:

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)

Wie kann ich das machen?

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

Antworten:


262

Sie übergeben die Ausnahme direkt an den Logger, z

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

Es liegt an log4j, den Stack-Trace zu rendern.


32
Der Logger nimmt ein Objekt als erstes Argument und führt es zu String (). Das zweite Argument muss jedoch ein Throwable sein und zeigt den Stack-Trace an.
Peter Lawrey

1
Ich weiß nie, was ich in den ersten String stecken soll, normalerweise mache ich das einfach, log.error(e.getLocalizedMessage(), e)was völlig überflüssig ist. Behandelt es eine Null für das erste Argument?
Mark Peters

5
@Mark: Versuchen Sie, ihm eine Nachricht zu geben, die für den Kontext relevanter ist als die Nachricht der Ausnahme, z. B. was hat sie damals tatsächlich versucht?
Skaffman

2
@Mark Peters, Ein gutes Beispiel könnte sein, die Argumente in der aktuellen Methode als Nachricht zu protokollieren oder - für eine FileNotFound-Ausnahme den vollständigen Namen des Pfads, der geöffnet werden soll. Alles, was Ihnen helfen kann, herauszufinden, was falsch ist - denken Sie nur, Sie können die Situation nicht debuggen.
Thorbjørn Ravn Andersen

1
@skaffman: Eigentlich verwende ich log4j-1.2.8.jarund ich wollte alles stackTracein meiner Protokolldatei drucken, also habe ich es wie oben erwähnt versucht, aber es wird nur in meiner Protokolldatei gedruckt nullPointerException. Ich wurde für meinen Code verwendet e.printStackTrace(), der alle Spuren druckt. Warum diese Kolavery?
Yubaraj

9

Wenn Sie einen Stacktrace ohne Ausnahme protokollieren möchten, gehen Sie wie folgt vor:

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 für den System.lineSeparator (), dies half mir, eine Stapelverfolgung zu drucken, die ich als Antwort von einem entfernten Dienst erhielt
Stephanie

1
was ich gesucht habe, aber Sie sollten StringBuilder hier verwenden
Xerus

9

Sie können die Stapelverfolgung auch als Zeichenfolge über abrufen ExceptionUtils.getStackTrace.

Siehe: ExceptionUtils.java

Ich benutze es nur für log.debug, um log.erroreinfach zu halten .


4

Nur weil es mir passiert ist und nützlich sein kann. Wenn du das tust

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

Sie erhalten den Header der Ausnahme und nicht den gesamten Stacktrace. Weil der Logger denkt, dass Sie einen String übergeben. Mach es ohne, {}wie Skaffman sagte


1
Sicherlich erhalten Sie hier eine vollständige Stapelverfolgung, aber das {} wird auch wörtlich gedruckt (ohne Substitution)?
k1eran

1
Sei dir nicht so sicher, mein Freund! Es hat bei mir nicht funktioniert, ich habe nur den Header bekommen. Es könnte jedoch von der Version von log4j abhängen
iberbeu

@iberbeu ist richtig, weil Throwable.toString()es keinen Stacktrace zurückgibt . (Angenommen, Sie verwenden einen Logger, der weiß, was mit '{}' zu tun ist.)

3

Die Antwort von skaffman ist definitiv die richtige Antwort. Alle Logger Methoden wie error(), warn(), info(), debug()nehmen Throwable als zweiten Parameter:

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

Sie können Stacktrace jedoch auch als String extrahieren. Manchmal kann es nützlich sein, wenn Sie die Formatierungsfunktion mit dem Platzhalter "{}" nutzen möchten - siehe Methode. Wenn Sie void info(String var1, Object... var2);in diesem Fall einen Stacktrace als String haben, können Sie tatsächlich Folgendes tun:

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

Dadurch werden die parametrisierte Nachricht und die Stapelverfolgung am Ende auf dieselbe Weise gedruckt wie bei der Methode: logger.error("error: ", e);

Ich habe tatsächlich eine Open-Source-Bibliothek geschrieben, die ein Dienstprogramm zum Extrahieren eines Stacktraces als String enthält, mit der Option, Rauschen aus dem Stacktrace intelligent herauszufiltern. Das heißt, wenn Sie das Paketpräfix angeben, an dem Sie interessiert sind, wird Ihr extrahierter Stacktrace aus einigen irrelevanten Teilen herausgefiltert und Sie erhalten sehr umfangreiche Informationen. Hier ist der Link zu dem Artikel, der erklärt, welche Dienstprogramme die Bibliothek hat und wo sie erhältlich ist (sowohl als Maven-Artefakte als auch als Git-Quellen) und wie man sie auch verwendet. Open Source Java-Bibliothek mit Stack-Trace-Filterung, Silent String-Parsing-Unicode-Konverter und Versionsvergleich Siehe Abschnitt " Stacktrace-Rauschfilter "


Eine begrabene aber nette Antwort.
Payne

Danke, @payne. Ich
freue

2

Diese Antwort bezieht sich möglicherweise nicht auf die gestellte Frage, sondern auf den Titel der Frage.

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

ODER

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

ODER

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

1

In Log4j 2 können Sie Logger.catching () verwenden , um einen Stacktrace von einer Ausnahme zu protokollieren, die abgefangen wurde.

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

0

Dies wäre eine gute log4j-Fehler- / Ausnahmeprotokollierung - lesbar durch Splunk / andere Protokollierung / Überwachung s / w. Alles ist eine Form eines Schlüssel-Wert-Paares. log4j würde den Stack-Trace von Exception obj erhaltene

    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

Sie können den folgenden Code verwenden:

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


    }

}

Hier können Sie einfach anrufen: LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

Es wird stackTrace in Ihr Protokoll drucken.


-2

Erstellen Sie dies 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);
        }
    };
}
}

Nennen Sie dies in Ihrem Code

StdOutErrLog.tieSystemOutAndErrToLog();
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.