Comment enregistrer autant d’informations que possible pour une exception Java?

Il y a un problème commun que j’ai rencontré à quelques resockets lors de la journalisation des exceptions. Il semble y avoir différents types à traiter. Par exemple, certains enveloppent d’autres exceptions, d’autres n’ont aucun message – juste un type.

La plupart du code que j’ai vu en journal Exceptions utilisant getMessage() ou toSsortingng( ) mais qui ne capturent pas toujours toutes les informations nécessaires pour identifier le problème – d’autres méthodes telles que getCause() et getStackTrace() fournissent parfois des informations supplémentaires.

Par exemple, l’exception que je regarde actuellement dans ma fenêtre Eclipse Inspect est une exception InvocationTargetException . L’exception elle-même n’a aucune cause, aucun message, aucun stacktrace … mais la cible de getCause () est InvalidUseOfMatchersException avec ces détails renseignés.

Donc, ma question est la suivante: Étant donné une exception de tout type en entrée, veuillez fournir une méthode unique qui produira une chaîne de caractères bien formatée contenant toutes les informations pertinentes sur l’exception (par exemple, appeler récursivement getCause() entre autres?) J’allais presque avoir un coup de main à moi-même, mais je ne veux pas vraiment réinventer la roue – une telle chose doit sûrement avoir été faite plusieurs fois auparavant?

S’il vous plaît, ne me pointez pas vers une structure de journalisation ou un utilitaire particulier pour ce faire. Je recherche un fragment de code plutôt qu’une bibliothèque, car je n’ai pas le droit d’append des dépendances externes au projet sur lequel je travaille et il est en fait enregistré sur une partie d’une page Web plutôt que sur un fichier. S’il s’agit de copier le fragment de code hors d’un tel framework (et de l’atsortingbuer), c’est bien 🙂

Le package java.util.logging est standard dans Java SE . Son Logger inclut une méthode de journal surchargée qui accepte les objects Throwable . Il enregistrera les emstackments des exceptions et leur cause pour vous.

Par exemple:

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

Va se connecter:

 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) 

En interne, cela fait exactement ce que @ philipp-wendler suggère, soit dit en passant. Voir le code source de SimpleFormatter.java . Ceci est juste une interface de niveau supérieur.

Quel est le problème avec la méthode printStacktrace() fournie par Throwable (et donc toutes les exceptions)? Il affiche toutes les informations demandées, y compris le type, le message et la trace de la stack de l’exception racine et de toutes les causes (nestedes). Dans Java 7, il vous montre même les informations sur les exceptions “supprimées” qui pourraient se produire dans une instruction try-with-resources.

Bien sûr, vous ne voudriez pas écrire dans System.err , ce que fait la version no-argument de la méthode, utilisez donc une des surcharges disponibles.

En particulier, si vous voulez juste obtenir une chaîne:

  Exception e = ... SsortingngWriter sw = new SsortingngWriter(); e.printStackTrace(new PrintWriter(sw)); Ssortingng exceptionDetails = sw.toSsortingng(); 

Si vous utilisez la grande bibliothèque Guava , elle fournit une méthode utilitaire pour cela: com.google.common.base.Throwables#getStackTraceAsSsortingng(Throwable) .

Cela devrait être assez simple si vous utilisez LogBack ou SLF4J. Je le fais comme ci-dessous

 //imports import org.slf4j.Logger; import org.slf4j.LoggerFactory; //Initialize logger Logger logger = LoggerFactory.getLogger(.class); try { //try something } catch(Exception e){ //Actual logging of error logger.error("some message", e); } 

Quelque chose que je fais est d’avoir une méthode statique qui gère toutes les exceptions et j’ajoute le journal à un JOptionPane pour le montrer à l’utilisateur, mais vous pouvez écrire le résultat dans un fichier dans FileWriter enveloppé dans un BufeeredWriter . Pour la méthode statique principale, pour capturer les exceptions non retenues que je fais:

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

Et quant à la méthode:

 public static void handleExceptions( Throwable ex, boolean shutDown ) { JOptionPane.showMessageDialog( null, "A CRITICAL ERROR APPENED!\n", "SYSTEM FAIL", JOptionPane.ERROR_MESSAGE ); SsortingngBuilder sb = new SsortingngBuilder(ex.toSsortingng()); 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); } } Ssortingng trace = sb.toSsortingng(); 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 ); } } 

Dans votre cas, au lieu de “crier” à l’utilisateur, vous pourriez écrire un journal comme je vous l’avais dit auparavant:

 Ssortingng trace = sb.toSsortingng(); 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... } } 

J’espère que j’ai aidé.

Bonne journée. 🙂

Un script de journalisation que j’ai écrit il y a quelque temps peut vous aider, même si ce n’est pas exactement ce que vous voulez. Il agit comme un System.out.println mais avec beaucoup plus d’ informations sur StackTrace, etc. Il fournit également du texte cliquable pour Eclipse:

 private static final SimpleDateFormat extended = new SimpleDateFormat( "dd MMM yyyy (HH:mm:ss) zz" ); public static java.util.logging.Logger initLogger(final Ssortingng 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 Ssortingng format(final LogRecord record) { StackTraceElement[] trace = new Throwable().getStackTrace(); Ssortingng 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 Ssortingng time = "<" + extended.format( new Date( record.getMillis() ) ) + "> "; SsortingngBuilder level = new SsortingngBuilder("[" + 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 ) /* sortingm if too long */ thread = thread.subssortingng( 0, 16 ) + "..."; else { SsortingngBuilder sb = new SsortingngBuilder(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; } 

Notez ces sorties sur la console, vous pouvez changer cela, voir http://docs.oracle.com/javase/1.4.2/docs/api/java/util/logging/Logger.html pour plus d'informations à ce sujet.

Maintenant, ce qui suit fera probablement ce que vous voulez. Il parcourra toutes les causes d'un object Throwable et le sauvegardera dans une chaîne. Notez que ceci n'utilise pas SsortingngBuilder , vous pouvez donc l'optimiser en le modifiant.

 Throwable e = ... Ssortingng detail = e.getClass().getName() + ": " + e.getMessage(); for( final StackTraceElement s : e.getStackTrace() ) detail += "\n\t" + s.toSsortingng(); while( ( e = e.getCause() ) != null ) { detail += "\nCaused by: "; for( final StackTraceElement s : e.getStackTrace() ) detail += "\n\t" + s.toSsortingng(); } 

Cordialement,
Danyel

Vous pouvez également utiliser les ExceptionsUtils d’Apache .

Exemple:

 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(Ssortingng[] args) { try{ Ssortingng[] avengers = null; System.out.println("Size: "+avengers.length); } catch (NullPointerException e){ logger.info(ExceptionUtils.getFullStackTrace(e)); } } } 

Sortie de la console:

 java.lang.NullPointerException at com.aimlessfist.avengers.ironman.Test.main(Test.java:11)