Como enviar um stacktrace para o log4j?

152

Digamos que você tenha capturado uma exceção e obtenha o seguinte na saída padrão (como, por exemplo, o console) se você fizer um 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)

Agora, quero enviar isso para um logger como, digamos, log4j para obter o seguinte:

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)

Como posso fazer isso?

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

Respostas:

262

Você passa a exceção diretamente para o criador de logs, por exemplo

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

Cabe ao log4j renderizar o rastreamento da pilha.

skaffman
fonte
32
O criador de logs pega um objeto como seu primeiro argumento e o envia paraString (). No entanto, o segundo argumento deve ser um Throwable e exibe o rastreamento da pilha.
Peter Lawrey
1
Eu nunca sei o que colocar na primeira String, geralmente acabo fazendo o log.error(e.getLocalizedMessage(), e)que é totalmente redundante. Ele lida com um nulo para o primeiro argumento?
Mark3
5
@ Mark: Tente dar uma mensagem mais pertinente ao contexto do que a mensagem da exceção, por exemplo, o que ela estava realmente tentando fazer no momento?
skaffman
2
@ Mark Peters, Um bom exemplo pode ser o de registrar os argumentos no método atual como a mensagem ou - para uma exceção FileNotFound, o nome completo do caminho que foi tentado abrir. Qualquer coisa que possa ajudá-lo a descobrir o que está errado - pense que você não pode depurar a situação.
Thorbjørn Ravn Andersen
1
@skaffman: Na verdade, estou usando log4j-1.2.8.jare queria imprimir tudo stackTraceno meu arquivo de log, então tentei como você mencionou acima, mas está imprimindo apenas no meu arquivo de log nullPointerException. Eu fui usado no meu código e.printStackTrace()que imprime todos os rastreamentos. Por que esse Kolavery?
Yubaraj
9

Se você deseja registrar um rastreamento de pilha sem envolver uma exceção, faça o seguinte:

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
fonte
3
+1 para o System.lineSeparator (), isso me ajudou a imprimir um stacktrace que eu tenho como uma resposta de um serviço remoto
Stephanie
1
o que eu tenho procurado, mas você deve usar StringBuilder aqui
Xerus
9

Você também pode obter o rastreamento de pilha como string via ExceptionUtils.getStackTrace.

Consulte: ExceptionUtils.java

Eu o uso apenas para log.debug, para manter a log.errorsimplicidade.

ktsujister
fonte
4

Só porque aconteceu comigo e pode ser útil. Se você fizer isto

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

você receberá o cabeçalho da exceção e não o rastreamento de pilha inteiro. Porque o criador de logs pensará que você está passando uma String. Faça isso {}como skaffman disse

iberbeu
fonte
1
Certamente você obterá todo o rastreamento da pilha aqui, no entanto, o {} também será impresso literalmente (sem nenhuma substituição)?
K1eran
1
não tenha tanta certeza meu amigo! Não funcionou para mim, recebi apenas o cabeçalho. Poderia depender da versão do log4j embora
iberbeu 25/02
@iberbeu está certo porque Throwable.toString()não retorna um rastreamento de pilha. (Supondo que você está usando um registrador de que sabe o que fazer para com '{}'.)
4

A resposta de skaffman é definitivamente a resposta correta. Todos os métodos logger, como error(), warn(), info(), debug()tomar Throwable como um segundo parâmetro:

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

No entanto, você pode extrair o stacktrace como uma String também. Às vezes, pode ser útil se você deseja tirar proveito do recurso de formatação usando o marcador de posição "{}" - consulte o método void info(String var1, Object... var2);Nesse caso, diga que você tem um rastreamento de pilha como String, então pode realmente fazer algo assim:

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

Isso imprimirá a mensagem parametrizada e o rastreamento de pilha no final da mesma maneira que no método: logger.error("error: ", e);

Na verdade, eu escrevi uma biblioteca de código aberto que possui um utilitário para extração de um stacktrace como uma String, com a opção de filtrar com inteligência o ruído do stacktrace. Ou seja, se você especificar o prefixo do pacote que está interessado no seu rastreamento de pilha extraído, será filtrado de algumas partes irrelevantes e o deixará com informações muito importantes. Aqui está o link para o artigo que explica quais utilitários a biblioteca possui e onde obtê-lo (como artefatos maven e fontes git) e como usá-lo também. Biblioteca Java de código aberto com filtragem de rastreamento de pilha, conversor Unicode de análise de string silenciosa e comparação de versões Consulte o parágrafo " Filtro de ruído Stacktrace "

Michael Gantman
fonte
1
Uma resposta enterrada, mas agradável.
Payne
Obrigado, @payne. Agradeço um bom feedback
Michael Gantman
2

Esta resposta pode não estar relacionada à pergunta, mas relacionada ao título da pergunta.

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
fonte
1

No Log4j 2, você pode usar Logger.catching () para registrar um rastreamento de pilha de uma exceção que foi capturada.

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

isso seria bom log4j log de erro / exceção - legível por splunk / outro log / monitoramento s / w. tudo é forma de par de valor-chave. log4j obteria o rastreamento de pilha da exceção obje

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

Você pode usar o código abaixo:

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


    }

}

Aqui você pode simplesmente ligar para: LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

Ele imprimirá o stackTrace no seu log.

Md. Sajedul Karim
fonte
-2

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

Chame isso em seu código

StdOutErrLog.tieSystemOutAndErrToLog();
user2281804
fonte