log4j druckt den Stacktrace nicht für Ausnahmen

70

Ich benutze log4j mit Tomcat. Wenn ich Ausnahmen in meinen JSPs protokolliere, werden Servlets:

private Logger _log = Logger.getLogger(this.getClass());
...
try{...} catch (Exception e) {
    _log.error("Error refreshing all prices", e);
}

Ich bekomme nur die erste Zeile der Ausnahme ohne Stacktrace.

17-Feb 17:37:45 ERROR AutoContrib: 175 - Ausnahme beim Veröffentlichen der CSV-Datei: java.lang.ArrayIndexOutOfBoundsException

Überhaupt nicht sehr hilfreich!

Meine Datei log4j.properties (/tomcat/common/classes/log4j.properties) sieht folgendermaßen aus:

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{dd-MMM HH:mm:ss} %5p %c{1}:%L - %m%n
log4j.appender.stdout.threshold=info

log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.maxFileSize=5000KB
log4j.appender.file.maxBackupIndex=10
log4j.appender.file.File=${catalina.home}/logs/web.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{dd-MMM HH:mm:ss} %5p %c{1}:%L - %m%n
log4j.appender.file.threshold=info

log4j.rootLogger=debug, stdout, file
Ryan
quelle
Soweit ich sehen kann, tun Sie alles so, wie es getan werden sollte ... Sie sollten den gesamten Stacktrace in Ihrem Protokoll sehen. Welche Version von log4j, Java und Tomcat verwenden Sie?
Manrico Corazzi
Wir verwenden Tomcat 5.5.17 und log4j-1.2.14 (Ich denke, wir werden in naher Zukunft auf tc6 upgraden, aber ich bin nicht sicher, ob das einen Unterschied machen wird?)
Ryan
Sie können den folgenden Thread anzeigen. Es hat vollständige Antwort stackoverflow.com/a/51655824/3073945
Md. Sajedul Karim

Antworten:

90

Eigentlich liegt es wahrscheinlich an einer Hotspot-Optimierung: Nachdem eine bestimmte Anzahl derselben Ausnahme ausgelöst wurde, wird der Ausdruck der Ablaufverfolgung beendet. Dies kann mit einem VM-Argument deaktiviert werden, siehe:

Von http://www.oracle.com/technetwork/java/javase/relnotes-139183.html :

Der Compiler in der Server-VM bietet jetzt korrekte Stack-Backtraces für alle "kalten" integrierten Ausnahmen. Aus Leistungsgründen kann die Methode neu kompiliert werden, wenn eine solche Ausnahme einige Male ausgelöst wird. Nach der Neukompilierung kann der Compiler eine schnellere Taktik mit vorab zugewiesenen Ausnahmen auswählen, die keine Stapelverfolgung bereitstellen. Verwenden Sie dieses neue Flag, um die Verwendung vorab zugewiesener Ausnahmen vollständig zu deaktivieren: -XX: -OmitStackTraceInFastThrow.

Mehr hier:

http://jawspeak.com/2010/05/26/hotspot-caused-exceptions-to-lose-their-stack-traces-in-production-and-the-fix/

minimo
quelle
5
Warum Java ... warum ...?
JTW
23

Was Sie gepostet haben, sollte den Stack-Trace anzeigen, wie im Javadoc angegeben .

Beachten Sie, dass logger.error(ex)der Stack-Trace nicht protokolliert wird , wenn Sie keine Nachricht einfügen (und nur aufrufen ).

Objekte
quelle
3
Ah. Da ist es. Das hat mich gebissen. Durch das Protokollieren eines Fehlers wird die Stapelverfolgung nicht gedruckt. Sie müssen eine Nachricht mit dem Fehler protokollieren, um dies zu erhalten.
Rbwhitaker
Das war hilfreich. Vielen Dank. Können wir log4j so konfigurieren, dass eine vollständige Ablaufverfolgung angezeigt wird, auch wenn wir nur das Ausnahmeobjekt bereitstellen?
Charles Morin
20

Es gibt zwei überladene Methoden für die Fehlermethode.

  1. logger.error(ex);
  2. logger.error("some oops string ", ex);

Wenn Sie die erste Methode verwenden, wird nur der Name der Ausnahme gedruckt. Wenn Sie die 2. Methode verwenden, wird eine Meldung zusammen mit einer Ausnahme angezeigt, die eine vollständige Stapelverfolgung ähnlich der e.printStackTrace()Methode druckt .

Venkatesh Boya
quelle
Das war mein Fall. Vielen Dank!
Frankieta
7

Wie oben von @Luhar beantwortet, kämpfte ich mit der gleichen Sache und schließlich funktionierte dies für mich; Das Gute an diesem Ansatz ist, dass wir nicht an Einstellungen auf Systemebene wie JVM oder Log4J basteln müssen, da wir nie wissen, dass dies zu neuen unerwarteten Überraschungen führen kann!

try {

...
..

} catch (Exception er) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        er.printStackTrace(new PrintStream(os));
        LOGGER.error(new String(os.toByteArray()));
        //LOGGER.error(er);
}
Rockoder
quelle
1

Ich sehe nichts falsches an Ihrer Konfiguration. Versuchen Sie daher, log4jauf eine neuere (nicht unbedingt die neueste) Version zu aktualisieren .

Obwohl dies in diesem Fall nicht das Problem ist, sollten Sie Ihre Logger erstellen private static final

Bozho
quelle
1

Ich habe den fillStackTrace-Aufruf nicht verwendet, daher kann ich nicht kommentieren, ob dies funktioniert. Ein anderer Ansatz besteht darin, eine kleine Methode zu verwenden, die den formatierten Text aus einer Ausnahme zurückgibt.

public static String getStackTrace(Exception e)
{
    StringWriter sWriter = new StringWriter();
    PrintWriter pWriter = new PrintWriter(sWriter);
    e.printStackTrace(pWriter);
    return sWriter.toString();
}

In Ihren Protokollcode könnten Sie schreiben:

logger.error("An exception occurred: " + Utils.getStackTrace(e));
Luhar
quelle
Idealerweise
1

Sie können diese Codezeilen in Ihren catch-Block einfügen.

catch (SQLException e) {
            CharArrayWriter cw = new CharArrayWriter();
            PrintWriter w = new PrintWriter(cw);
            e.printStackTrace(w);
            w.close();
            String trace = cw.toString();

    log.error("This is complete stacktrace", trace);
}
Madhu
quelle
-1

Verwenden Sie Ihr Codebeispiel:

private static final Logger _log = Logger.getLogger(MyClass.class);
...
try{...} catch (Exception e) {
    //Change
    //_log.error("Error refreshing all prices", e);

   //To
    _log.error("Error refreshing all prices", e.fillInStackTrace());
}

Sie sehen alle Stapelverfolgung angezeigt.

PS. Machen Sie Logger zu einem Singleton ... (überprüfen Sie meine Erklärung) kurz nach der Erklärungpublic class MyClass {

Buhake Sindi
quelle
Danke für den Hinweis! Ich werde es jetzt versuchen. Übrigens, für den Singleton-Ansatz können Sie 'this' nicht mit dem statischen getLoggger () verwenden. Ich denke, ich kann getLogger (MyClass.class)
Ryan
Wahrer Ryan!. Dadurch wird die Instanziierung schneller, da der Singleton bereits nach der Erstellung vorhanden ist.
Buhake Sindi
4
Dadurch wird die Stapelverfolgung in den Status des aktuellen Threads geändert. Es wird nicht mehr die Stapelverfolgung für die ausgelöste Ausnahme sein
Objekte
2
Die Stapelverfolgung des Threads unterscheidet sich von der Stapelverfolgung der Ausnahme. Die Stapelverfolgung der Ausnahme zeigt, wo die Ausnahme aufgetreten ist, die Stapelverfolgung des Threads (in diesem Fall) zeigt, wo die Ausnahme abgefangen wurde.
Objekte
1
fillInStackTrace zeichnet die Ursache afaik nicht auf, sie (die Ursache) wird festgelegt, wenn die Ausnahme erstellt wird (fillInStackTrace wird an diesem Punkt auch aufgerufen)
Objekte