Come inviare uno stacktrace a log4j?


152

Supponi di prendere un'eccezione e ottieni quanto segue sull'output standard (come, diciamo, la console) se fai 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)

Ora voglio inviare questo invece a un logger come, diciamo, log4j per ottenere quanto segue:

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)

Come posso fare questo?

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

Risposte:


262

Si passa l'eccezione direttamente al logger, ad es

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

Sta a log4j rendere il rendering dello stack stack.


32
Il logger prende un oggetto per il suo primo argomento e lo toString (). Tuttavia, il secondo argomento deve essere Throwable e visualizza la traccia dello stack.
Peter Lawrey,

1
Non so mai cosa inserire nella prima stringa, di solito finisco per fare il log.error(e.getLocalizedMessage(), e)che è totalmente ridondante. Gestisce un null per il primo argomento?
Mark Peters,

5
@Mark: prova a dargli un messaggio più pertinente al contesto rispetto al messaggio dell'eccezione, ad esempio cosa stava cercando di fare in quel momento?
Skaffman,

2
@Mark Peters, Un buon esempio potrebbe essere quello di registrare gli argomenti nel metodo corrente come messaggio, oppure - per un'eccezione FileNotFound, il nome completo del percorso che si è tentato di aprire. Tutto ciò che può aiutarti a scoprire cosa c'è che non va - pensa solo di non poter eseguire il debug della situazione.
Thorbjørn Ravn Andersen,

1
@skaffman: In realtà sto usando log4j-1.2.8.jare volevo stampare tutto stackTracesul mio file di registro, quindi ho provato come sopra menzionato ma sta stampando solo sul mio file di registro nullPointerException. Sono stato usato sul mio codice e.printStackTrace()stampa tutte le tracce. Perché questo Kolavery?
Yubaraj,

9

Se si desidera registrare uno stacktrace senza comportare un'eccezione, procedere come segue:

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 per System.lineSeparator (), questo mi ha aiutato a stampare uno stack stack che ho ricevuto come risposta da un servizio remoto
Stephanie

1
quello che ho cercato, ma dovresti usare StringBuilder qui
Xerus

9

Puoi anche ottenere la traccia dello stack come stringa tramite ExceptionUtils.getStackTrace.

Vedi: ExceptionUtils.java

Lo uso solo per log.debug, per log.errorsemplicità.


4

Solo perché è successo a me e può essere utile. Se lo fai

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

otterrai l'intestazione dell'eccezione e non l'intero stacktrace. Perché il logger penserà che stai passando una stringa. Fallo senza {}come ha detto Skaffman


1
Sicuramente otterrai una traccia dell'intero stack qui, tuttavia {} verrà stampato anche testualmente (senza alcuna sostituzione)?
k1eran,

1
non essere così sicuro amico mio! Per me non ha funzionato, ho solo l'intestazione. Potrebbe dipendere dalla versione di log4j
iberbeu,

@iberbeu ha ragione perché Throwable.toString()non restituisce uno stacktrace. (Supponendo che tu stia utilizzando un logger che sa cosa fare con '{}'.)

4

La risposta di Skaffman è sicuramente la risposta corretta. Tutti i metodi di logger, come error(), warn(), info(), debug()prendono Throwable come secondo parametro:

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

Tuttavia, è possibile estrarre stacktrace anche come stringa. A volte potrebbe essere utile se si desidera sfruttare la funzionalità di formattazione utilizzando il segnaposto "{}" - vedere il metodo void info(String var1, Object... var2);In questo caso dire che si dispone di uno stacktrace come String, quindi si può effettivamente fare qualcosa del genere:

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

Questo stamperà il messaggio parametrizzato e lo stacktrace alla fine allo stesso modo del metodo: logger.error("error: ", e);

In realtà ho scritto una libreria open source che ha un'utilità per l'estrazione di uno stacktrace come String con un'opzione per filtrare in modo intelligente un po 'di rumore dallo stacktrace. Vale a dire se specifichi il prefisso del pacchetto che ti interessa per il tuo stacktrace estratto verrebbe filtrato da alcune parti irrilevanti e ti lascerebbe con informazioni molto consistenti. Ecco il link all'articolo che spiega quali utilità ha la libreria e dove trovarla (sia come manufatti maven che come fonti git) e come usarla pure. Libreria Java Open Source con filtro di traccia stack, analisi stringhe Silent Convertitore Unicode e confronto versioni Vedi il paragrafo " Filtro rumore Stacktrace "


1
Una risposta sepolta ma carina.
Payne,

Grazie @payne. Apprezzo un bel feedback
Michael Gantman,

2

Questa risposta potrebbe non essere correlata alla domanda posta ma legata al titolo della domanda.

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

O

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

O

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

1

In Log4j 2, è possibile utilizzare Logger.catching () per registrare una stack stack da un'eccezione rilevata.

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

0

questo sarebbe un buon log4j errore / registrazione delle eccezioni - leggibile da splunk / altra registrazione / monitoraggio s / w. tutto è una forma di coppia chiave-valore. log4j otterrebbe la traccia dello stack dall'eccezione obje

    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

Puoi usare il seguente codice:

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


    }

}

Qui puoi semplicemente chiamare: LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

Stamperà stackTrace nel tuo registro.


-2

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

Chiamalo nel tuo codice

StdOutErrLog.tieSystemOutAndErrToLog();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.