Es gibt ein häufiges Problem, auf das ich beim Protokollieren von Ausnahmen in Java einige Male gestoßen bin. Es scheint verschiedene Arten zu geben, mit denen man sich auseinandersetzen muss. ZB schließen einige andere Ausnahmen ein und einige haben überhaupt keine Nachricht – nur einen Typ.
Der meiste Code, den ich gesehen habe, protokolliert eine Ausnahme, indem er eine von beiden verwendet getMessage() oder toString(). Diese Methoden erfassen jedoch nicht immer alle Informationen, die zum Lokalisieren des Problems erforderlich sind – andere Methoden wie z getCause() und getStackTrace() stellen manchmal zusätzliche Informationen bereit.
Die Ausnahme, die ich mir gerade in meinem Eclipse-Inspect-Fenster ansehe, ist zum Beispiel eine InvocationTargetException. Die Ausnahme selbst hat keine Ursache, keine Nachricht, kein Stacktrace … aber das Ziel von getCause() ist es InvalidUseOfMatchersExceptionmit diesen Details ausgefüllt.
Also meine Frage ist: Angesichts einer Ausnahme von irgendein type als Eingabe, geben Sie bitte eine einzelne Methode an, die eine schön formatierte Zeichenfolge ausgibt, die enthält alle relevante Informationen über die Ausnahme (z. B. möglicherweise rekursives Aufrufen getCause() unter anderem?) Bevor ich gepostet habe, wollte ich es fast selbst versuchen, aber ich möchte das Rad wirklich nicht neu erfinden – so etwas muss doch schon oft gemacht worden sein …?
fluchen
Das java.util.logging Paket ist standardmäßig drin Java SE. Es ist Logger enthält eine überladene Protokollmethode, die akzeptiert Throwable Objekte. Es protokolliert Stacktraces von Ausnahmen und deren Ursache für Sie.
Zum Beispiel:
import java.util.logging.Level;
import java.util.logging.Logger;
[...]
Logger logger = Logger.getAnonymousLogger();
Exception e1 = new Exception();
Exception e2 = new Exception(e1);
logger.log(Level.SEVERE, "an exception was thrown", e2);
Werde protokollieren:
SEVERE: an exception was thrown
java.lang.Exception: java.lang.Exception
at LogStacktrace.main(LogStacktrace.java:21)
Caused by: java.lang.Exception
at LogStacktrace.main(LogStacktrace.java:20)
Intern macht das übrigens genau das, was @philipp-wendler vorschlägt. Siehe die Quellcode für SimpleFormatter.java. Dies ist nur eine Schnittstelle auf höherer Ebene.
Denken Sie daran, dass Sie bei Verwendung eines benutzerdefinierten Formatierers speziell die Verwendung von Throwables unterstützen müssen (ich habe gerade Oracle-Code kopiert), da dies sonst nicht funktioniert.
Diese Antwort war hilfreich. Ich habe getestet, ob ich Ausnahmen so protokollieren kann, dass alle Informationen über den Fehler (einschließlich der Fehlermeldung der tief verschachtelten ursprünglichen Ausnahme) enthalten sind und dass das Programm auch weiterhin mehr Arbeit verarbeiten kann. Das hat gut funktioniert. Die protokollierte Zeichenfolge enthalten INFO: could not complete job for user Matt, com.mattwelke.Main$MathException: failed to do mathund Caused by: java.lang.IllegalArgumentException: you tried to divide 10.0 by 0. (was bedeutet, dass ich den gesamten Fehlerkontext, den ich brauchte, in den Protokollen erhalten habe). Ich kann mir vorstellen, dass dies auch mit SLF4J gut funktionieren würde.
– Matt Welke
24. Januar um 5:36 Uhr
Harish Gokavarapu
Es sollte ganz einfach sein, wenn Sie LogBack oder SLF4J verwenden. Ich mache es wie folgt
Was ist los mit der printStacktrace() Methode zur Verfügung gestellt von Throwable (und damit jede Ausnahme)? Es zeigt alle angeforderten Informationen, einschließlich Typ, Nachricht und Stack-Trace der Root-Ausnahme und aller (verschachtelten) Ursachen. In Java 7 zeigt es Ihnen sogar die Informationen über “unterdrückte” Ausnahmen, die in einer try-with-resources-Anweisung auftreten können.
Natürlich würdest du nicht schreiben wollen System.errwas die Version der Methode ohne Argumente tut, also verwenden Sie stattdessen eine der verfügbaren Überladungen.
Insbesondere, wenn Sie nur einen String erhalten möchten:
Exception e = ...
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
Vielen Dank für Ihre Antwort, aber ich denke, alles, was printStacktrace() tut, schreibt den von getStacktrace() zurückgegebenen Stacktrace in den Fehlerstrom? Das ist nicht wirklich das, was ich suche. Denken Sie auch nicht, dass es in dem Fall funktionieren würde, in dem die Ausnahme eine andere Ausnahme umschließt.
– Steve Kammern
30. Januar 2013 um 14:50 Uhr
Die Überladungen von printStackStrace auf ein anderes Ziel schreiben, nicht in den Fehlerstrom. Und die gedruckten Informationen enthalten alle Ursachen, einschließlich ihres Typs, ihrer Nachricht, ihres Stack-Trace und (verschachtelter) Ursachen.
– Philipp Wendler
30. Januar 2013 um 14:53 Uhr
Probieren Sie einfach meine 3 Codezeilen aus, ich bin sicher, Sie werden zufrieden sein.
– Philipp Wendler
30. Januar 2013 um 14:53 Uhr
Es ist nicht erforderlich, Ihre eigene Version zu erstellen, Standard-J2SE bietet dies. Siehe meine Antwort.
– Fluch
30. Januar 2013 um 15:12 Uhr
@flup Warum würdest du das als “selbst rollen” betrachten? Diesen Weg tut Verwenden Sie dazu die Standard-Java-Methode.
– Philipp Wendler
30. Januar 2013 um 15:19 Uhr
Ein Protokollierungsskript, das ich vor einiger Zeit geschrieben habe, könnte hilfreich sein, obwohl es nicht genau das ist, was Sie wollen. Es verhält sich wie ein System.out.println, aber mit viel mehr Informationen über StackTrace usw. Es bietet auch anklickbaren Text für Eclipse:
private static final SimpleDateFormat extended = new SimpleDateFormat( "dd MMM yyyy (HH:mm:ss) zz" );
public static java.util.logging.Logger initLogger(final String name) {
final java.util.logging.Logger logger = java.util.logging.Logger.getLogger( name );
try {
Handler ch = new ConsoleHandler();
logger.addHandler( ch );
logger.setLevel( Level.ALL ); // Level selbst setzen
logger.setUseParentHandlers( false );
final java.util.logging.SimpleFormatter formatter = new SimpleFormatter() {
@Override
public synchronized String format(final LogRecord record) {
StackTraceElement[] trace = new Throwable().getStackTrace();
String clickable = "(" + trace[ 7 ].getFileName() + ":" + trace[ 7 ].getLineNumber() + ") ";
/* Clickable text in Console. */
for( int i = 8; i < trace.length; i++ ) {
/* 0 - 6 is the logging trace, 7 - x is the trace until log method was called */
if( trace[ i ].getFileName() == null )
continue;
clickable = "(" + trace[ i ].getFileName() + ":" + trace[ i ].getLineNumber() + ") -> " + clickable;
}
final String time = "<" + extended.format( new Date( record.getMillis() ) ) + "> ";
StringBuilder level = new StringBuilder("[" + record.getLevel() + "] ");
while( level.length() < 15 ) /* extend for tabby display */
level.append(" ");
StringBuilder name = new StringBuilder(record.getLoggerName()).append(": ");
while( name.length() < 15 ) /* extend for tabby display */
name.append(" ");
String thread = Thread.currentThread().getName();
if( thread.length() > 18 ) /* trim if too long */
thread = thread.substring( 0, 16 ) + "...";
else {
StringBuilder sb = new StringBuilder(thread);
while( sb.length() < 18 ) /* extend for tabby display */
sb.append(" ");
thread = sb.insert( 0, "Thread " ).toString();
}
final String message = "\"" + record.getMessage() + "\" ";
return level + time + thread + name + clickable + message + "\n";
}
};
ch.setFormatter( formatter );
ch.setLevel( Level.ALL );
} catch( final SecurityException e ) {
e.printStackTrace();
}
return logger;
}
Nun, das Folgende wird wahrscheinlich tun, was Sie wollen. Es durchläuft alle Ursachen eines Throwable und speichert es in einem String. Beachten Sie, dass dies nicht verwendet wird StringBuildersodass Sie ihn optimieren können, indem Sie ihn ändern.
Throwable e = ...
String detail = e.getClass().getName() + ": " + e.getMessage();
for( final StackTraceElement s : e.getStackTrace() )
detail += "\n\t" + s.toString();
while( ( e = e.getCause() ) != null ) {
detail += "\nCaused by: ";
for( final StackTraceElement s : e.getStackTrace() )
detail += "\n\t" + s.toString();
}
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.log4j.Logger;
public class Test {
static Logger logger = Logger.getLogger(Test.class);
public static void main(String[] args) {
try{
String[] avengers = null;
System.out.println("Size: "+avengers.length);
} catch (NullPointerException e){
logger.info(ExceptionUtils.getFullStackTrace(e));
}
}
}
Konsolenausgabe:
java.lang.NullPointerException
at com.aimlessfist.avengers.ironman.Test.main(Test.java:11)
Ab Version 3 der Sprachdienstprogramme wurde die Methode umbenannt in ExceptionUtils#getStackTrace(...)!
– ltlBeBoy
22. Juni um 14:31 Uhr
Saclyr Barlonium
Etwas, das ich tue, ist, eine statische Methode zu haben, die alle Ausnahmen behandelt, und ich füge das Protokoll zu einem JOptionPane hinzu, um es dem Benutzer anzuzeigen, aber Sie könnten das Ergebnis in eine Datei schreiben FileWriter eingewickelt in ein BufeeredWriter. Für die statische Hauptmethode mache ich Folgendes, um die nicht erfassten Ausnahmen abzufangen:
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
//Initializations...
}
});
Thread.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException( Thread t, Throwable ex ) {
handleExceptions( ex, true );
}
}
);
Und was die Methode angeht:
public static void handleExceptions( Throwable ex, boolean shutDown ) {
JOptionPane.showMessageDialog( null,
"A CRITICAL ERROR APPENED!\n",
"SYSTEM FAIL",
JOptionPane.ERROR_MESSAGE );
StringBuilder sb = new StringBuilder(ex.toString());
for (StackTraceElement ste : ex.getStackTrace()) {
sb.append("\n\tat ").append(ste);
}
while( (ex = ex.getCause()) != null ) {
sb.append("\n");
for (StackTraceElement ste : ex.getStackTrace()) {
sb.append("\n\tat ").append(ste);
}
}
String trace = sb.toString();
JOptionPane.showMessageDialog( null,
"PLEASE SEND ME THIS ERROR SO THAT I CAN FIX IT. \n\n" + trace,
"SYSTEM FAIL",
JOptionPane.ERROR_MESSAGE);
if( shutDown ) {
Runtime.getRuntime().exit( 0 );
}
}
In Ihrem Fall könnten Sie, anstatt den Benutzer anzuschreien, ein Protokoll schreiben, wie ich es Ihnen zuvor gesagt habe:
String trace = sb.toString();
File file = new File("mylog.txt");
FileWriter myFileWriter = null;
BufferedWriter myBufferedWriter = null;
try {
//with FileWriter(File file, boolean append) you can writer to
//the end of the file
myFileWriter = new FileWriter( file, true );
myBufferedWriter = new BufferedWriter( myFileWriter );
myBufferedWriter.write( trace );
}
catch ( IOException ex1 ) {
//Do as you want. Do you want to use recursive to handle
//this exception? I don't advise that. Trust me...
}
finally {
try {
myBufferedWriter.close();
}
catch ( IOException ex1 ) {
//Idem...
}
try {
myFileWriter.close();
}
catch ( IOException ex1 ) {
//Idem...
}
}
Ich hoffe, ich habe geholfen.
Einen schönen Tag noch. 🙂
Ab Version 3 der Sprachdienstprogramme wurde die Methode umbenannt in ExceptionUtils#getStackTrace(...)!
– ltlBeBoy
22. Juni um 14:31 Uhr
14247000cookie-checkWie protokolliere ich Ausnahmen in Java?yes