Jak wysłać stacktrace do log4j?

152

Powiedzmy, że wychwytujesz wyjątek i otrzymujesz następujące informacje na standardowym wyjściu (takim jak, powiedzmy, konsola), jeśli wykonujesz 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)

Teraz chcę wysłać to zamiast tego do rejestratora, takiego jak, powiedzmy, log4j, aby uzyskać następujące informacje:

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)

W jaki sposób mogę to zrobić?

try {
   ...
} catch (Exception e) {
    final String s;
    ...  // <-- What goes here?
    log.error( s );
}
Składnia T3rr0r
źródło

Odpowiedzi:

262

Wyjątek przekazujesz bezpośrednio do loggera np

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

Renderowanie śladu stosu zależy od log4j.

skaffman
źródło
32
Rejestrator przyjmuje obiekt jako pierwszy argument i toString () go. Jednak drugi argument musi być rzucany i wyświetla ślad stosu.
Peter Lawrey
1
Nigdy nie wiem, co włożyć do pierwszego ciągu, zwykle po prostu robię, log.error(e.getLocalizedMessage(), e)co jest całkowicie zbędne. Czy obsługuje wartość null dla pierwszego argumentu?
Mark Peters
5
@Mark: Spróbuj przekazać mu wiadomość, która jest bardziej adekwatna do kontekstu niż wiadomość o wyjątku, np. Co tak naprawdę próbował w tym czasie zrobić?
skaffman
2
@Mark Peters, Dobrym przykładem może być zapisanie argumentów do bieżącej metody jako komunikatu lub - w przypadku wyjątku FileNotFound - pełna nazwa ścieżki, którą próbowano otworzyć. Wszystko, co może pomóc Ci dowiedzieć się, co jest nie tak - po prostu pomyśl, że nie możesz debugować sytuacji.
Thorbjørn Ravn Andersen,
1
@skaffman: Właściwie używam log4j-1.2.8.jari chciałem wydrukować wszystko stackTracew moim pliku dziennika, więc próbowałem tak, jak wspomniałeś powyżej, ale drukuje tylko na moim pliku dziennika nullPointerException. Zostałem użyty w moim kodzie, e.printStackTrace()który wyświetla wszystkie ślady. Dlaczego ten Kolavery?
Yubaraj,
9

Jeśli chcesz zarejestrować ślad stosu bez angażowania wyjątku, zrób to:

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
źródło
3
+1 dla System.lineSeparator (), pomogło mi to wydrukować stos, który otrzymałem w odpowiedzi z usługi zdalnej
Stephanie
1
tego, czego szukałem, ale powinieneś użyć tutaj StringBuilder
Xerus
9

Możesz również pobrać ślad stosu jako ciąg znaków za pośrednictwem ExceptionUtils.getStackTrace.

Zobacz: ExceptionUtils.java

Używam go tylko log.debugdo log.errorprostoty.

ktsujister
źródło
4

Tylko dlatego, że mi się to przydarzyło i może być przydatne. Jeśli to zrobisz

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

otrzymasz nagłówek wyjątku, a nie cały ślad stosu. Ponieważ logger pomyśli, że przekazujesz String. Zrób to bez, {}jak powiedział skaffman

iberbeu
źródło
1
Z pewnością dostaniesz tutaj cały ślad stosu, jednak {} również zostanie wydrukowany dosłownie (bez żadnych podstawień)?
k1eran
1
nie bądź taki pewien, przyjacielu! Dla mnie to nie zadziałało, mam tylko nagłówek. Może to jednak zależeć od wersji log4j
iberbeu
@iberbeu ma rację, ponieważ Throwable.toString()nie zwraca śladu stosu. (Zakładając, że używasz loggera, który wie, co zrobić z '{}'.)
3

Odpowiedź od skaffmana jest zdecydowanie poprawna. Wszystkie metody logger takie jak error(), warn(), info(), debug()wziąć Throwable jako drugi parametr:

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

Możesz jednak również wyodrębnić stacktrace jako ciąg. Czasami może się przydać, jeśli chcesz skorzystać z funkcji formatowania przy użyciu void info(String var1, Object... var2);symbolu zastępczego „{}” - patrz metoda W tym przypadku powiedz, że masz ciąg znaków ze stosu, a następnie możesz zrobić coś takiego:

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

Spowoduje to wypisanie sparametryzowanego komunikatu i śladu stosu na końcu w taki sam sposób, jak w przypadku metody: logger.error("error: ", e);

Właściwie napisałem bibliotekę open source, która ma narzędzie do wyodrębniania śladu stosu jako ciąg znaków z opcją inteligentnego odfiltrowania szumu poza śladem stosu. To znaczy, jeśli określisz prefiks pakietu, który Cię interesuje, wyodrębniony ślad stosu zostanie odfiltrowany z niektórych nieistotnych części i pozostawi bardzo szczegółowe informacje. Oto link do artykułu, który wyjaśnia, jakie narzędzia ma biblioteka i skąd je zdobyć (zarówno jako artefakty mavena, jak i źródła git), a także jak z niego korzystać. Biblioteka Java Open Source z filtrowaniem śladów stosu, konwerterem Unicode Silent String i Porównanie wersji Zobacz akapit „ Filtr szumu stosu

Michael Gantman
źródło
Pogrzebana, ale miła odpowiedź.
payne
Dzięki, @payne. Doceniam miłą opinię
Michael Gantman
2

Ta odpowiedź może nie być związana z zadanym pytaniem, ale z tytułem pytania.

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

LUB

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

LUB

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for(StackTraceElement stackTrace: stackTraceElements){
    logger.debug(stackTrace.getClassName()+ "  "+ stackTrace.getMethodName()+" "+stackTrace.getLineNumber());
}
Kanagavelu Sugumar
źródło
1

W Log4j 2 można użyć Logger.catching (), aby zarejestrować ślad stosu z wychwyconego wyjątku.

    try {
        String msg = messages[messages.length];
        logger.error("An exception should have been thrown");
    } catch (Exception ex) {
        logger.catching(ex);
    }
mbonness
źródło
0

byłoby to dobre rejestrowanie błędów / wyjątków log4j - do odczytu przez splunk / inne logowanie / monitorowanie s / w. wszystko jest formą pary klucz-wartość. log4j pobierze ślad stosu z Exception obje

    try {
          ---
          ---
    } catch (Exception e) {
        log.error("api_name={} method={} _message=\"error description.\" msg={}", 
                  new Object[]{"api_name", "method_name", e.getMessage(), e});
    }
src3369
źródło
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
źródło
-1

Możesz użyć poniższego kodu:

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


    }

}

Tutaj możesz po prostu zadzwonić: LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

Wyświetli stackTrace w twoim dzienniku.

Md. Sajedul Karim
źródło
-2

Utwórz to 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);
        }
    };
}
}

Nazwij to w swoim kodzie

StdOutErrLog.tieSystemOutAndErrToLog();
user2281804
źródło