Comment envoyer un stacktrace à log4j?

152

Disons que vous attrapez une exception et obtenez ce qui suit sur la sortie standard (comme, par exemple, la console) si vous faites un 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)

Maintenant, je veux envoyer ceci à la place à un enregistreur comme, par exemple, log4j pour obtenir ce qui suit:

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)

Comment puis-je faire ceci?

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

Réponses:

262

Vous transmettez l'exception directement à l'enregistreur, par exemple

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

C'est à log4j de rendre la trace de la pile.

skaffman
la source
32
L'enregistreur prend un objet comme premier argument et le toString (). Cependant, le deuxième argument doit être un Throwable et affiche la trace de la pile.
Peter Lawrey
1
Je ne sais jamais quoi mettre dans la première chaîne, généralement je finis par faire log.error(e.getLocalizedMessage(), e)ce qui est totalement redondant. Gère-t-il un null pour le premier argument?
Mark Peters
5
@Mark: Essayez de lui donner un message plus pertinent pour le contexte que le message de l'exception, par exemple qu'est-ce qu'il essayait réellement de faire à l'époque?
skaffman
2
@Mark Peters, Un bon exemple pourrait être de consigner les arguments de la méthode actuelle comme message, ou - pour une exception FileNotFound, le nom complet du chemin qui a été tenté d'être ouvert. Tout ce qui peut vous aider à découvrir ce qui ne va pas - pensez simplement que vous ne pouvez pas déboguer la situation.
Thorbjørn Ravn Andersen
1
@skaffman: En fait, j'utilise log4j-1.2.8.jaret je voulais tout imprimer stackTracesur mon fichier journal, j'ai donc essayé comme ci-dessus, mais j'imprime uniquement sur mon fichier journal nullPointerException. J'ai été utilisé sur mon code, e.printStackTrace()il imprime toute trace. Pourquoi ce Kolavery?
Yubaraj
9

Si vous souhaitez enregistrer un stacktrace sans impliquer une exception, procédez comme suit:

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);
Borjab
la source
3
+1 pour System.lineSeparator (), cela m'a aidé à imprimer un stacktrace que j'ai obtenu en réponse à un service distant
Stephanie
1
ce que j'ai recherché, mais vous devriez utiliser StringBuilder ici
Xerus
9

Vous pouvez également obtenir la trace de la pile sous forme de chaîne via ExceptionUtils.getStackTrace.

Voir: ExceptionUtils.java

Je l'utilise uniquement pour log.debug, pour rester log.errorsimple.

ktsujister
la source
4

Tout simplement parce que cela m'est arrivé et peut être utile. Si tu fais ça

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

vous obtiendrez l'en-tête de l'exception et non l'intégralité du stacktrace. Parce que l'enregistreur pensera que vous passez une chaîne. Faites-le sans {}comme le dit skaffman

iberbeu
la source
1
Vous obtiendrez sûrement toute la trace de la pile ici, mais le {} sera également affiché textuellement (sans aucune substitution)?
k1eran
1
ne sois pas si sûr mon ami! Cela n'a pas fonctionné pour moi, je n'ai eu que l'en-tête. Cela pourrait dépendre de la version de log4j
iberbeu
@iberbeu a raison car Throwable.toString()ne renvoie pas de trace de pile. (En supposant que vous utilisez un enregistreur qui sait quoi faire avec '{}'.)
4

La réponse de skaffman est certainement la bonne réponse. Toutes les méthodes de l' enregistreur tels que error(), warn(), info(), debug()prennent Throwable comme second paramètre:

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

Cependant, vous pouvez également extraire stacktrace sous forme de chaîne. Parfois, cela peut être utile si vous souhaitez profiter de la fonctionnalité de mise en forme en utilisant l'espace réservé "{}" - voir la méthode void info(String var1, Object... var2);Dans ce cas, disons que vous avez un stacktrace sous forme de chaîne, alors vous pouvez faire quelque chose comme ceci:

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

Cela affichera le message paramétré et le stacktrace à la fin de la même manière que pour la méthode: logger.error("error: ", e);

En fait, j'ai écrit une bibliothèque open source qui a un utilitaire pour l'extraction d'un stacktrace en tant que chaîne avec une option pour filtrer intelligemment certains bruits de stacktrace. C'est-à-dire que si vous spécifiez le préfixe de package qui vous intéresse, votre stacktrace extrait serait filtré de certaines parties non pertinentes et vous laisserait des informations très détaillées. Voici le lien vers l'article qui explique les utilitaires de la bibliothèque et où l'obtenir (à la fois comme artefacts maven et sources git) et comment l'utiliser également. Bibliothèque Java Open Source avec filtrage de trace de pile, analyse de Silent String, convertisseur Unicode et comparaison de version Voir le paragraphe " Filtre de bruit Stacktrace "

Michael Gantman
la source
1
Une réponse enterrée mais agréable.
payne
Merci, @payne. J'apprécie un bon retour
Michael Gantman
2

Cette réponse peut ne pas être liée à la question posée mais liée au titre de la question.

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

OU

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

OU

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

Dans Log4j 2, vous pouvez utiliser Logger.catching () pour enregistrer un stacktrace à partir d'une exception qui a été interceptée.

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

ce serait une bonne journalisation des erreurs / exceptions log4j - lisible par splunk / autre journalisation / surveillance s / w. tout est forme de paire clé-valeur. log4j obtiendrait la trace de la pile à partir de l'obj d'exceptione

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

catch (Throwable t) {
    logger.error("any message" + t);
    StackTraceElement[] s = t.getStackTrace();
    for(StackTraceElement e : s){
        logger.error("\tat " + e);
    }   
}
Rajdeep Acharyya Chowdhury
la source
-1

Vous pouvez utiliser le code ci-dessous:

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


    }

}

Ici, vous pouvez simplement appeler: LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

Il imprimera stackTrace dans votre journal.

Md. Sajedul Karim
la source
-2

Créez ceci 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);
        }
    };
}
}

Appelez ça dans votre code

StdOutErrLog.tieSystemOutAndErrToLog();
user2281804
la source