如何将堆栈跟踪发送到log4j?


152

假设您执行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)

现在,我想将其发送给log4j之类的记录器,以获取以下信息:

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)

我怎样才能做到这一点?

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

Answers:


262

您将异常直接传递给记录器,例如

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

取决于log4j来呈现堆栈跟踪。


32
记录器将对象作为第一个参数,并将其toString()。但是,第二个参数必须是Throwable并显示堆栈跟踪。
彼得·劳瑞

1
我永远不知道将什么填充到第一个String中,通常我只是做log.error(e.getLocalizedMessage(), e)那完全是多余的。它为第一个参数处理null吗?
马克·彼得斯

5
@Mark:尝试给它提供一个比异常的消息与上下文更相关的消息,例如,当时它实际上在试图做什么?
skaffman

2
@Mark Peters,一个很好的例子是将当前方法的参数记录为消息,或者-对于FileNotFound异常,尝试打开的路径的全名。任何可以帮助您找出问题所在的方法-认为您无法调试这种情况。
托尔比约恩Ravn的安德森

1
@skaffman:实际上我正在使用log4j-1.2.8.jar,我想stackTrace在我的日志文件上打印所有内容,因此我尝试了上面提到的内容,但是只在我的日志文件上打印nullPointerException。我在我的代码上使用过,e.printStackTrace()它可以打印所有跟踪。为什么要这样Kolavery?
Yubaraj

9

如果要在不涉及异常的情况下记录堆栈跟踪,请执行以下操作:

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为System.lineSeparator(),这帮助我打印了一个堆栈跟踪,作为从远程服务获得的响应
Stephanie

1
我已经搜索过的内容,但是您应该在这里使用StringBuilder
Xerus

9

您还可以通过获取字符串形式的堆栈跟踪ExceptionUtils.getStackTrace

请参阅:ExceptionUtils.java

我只将它用于log.debug,以保持log.error简单。


4

只是因为它发生在我身上并且可能有用。如果你这样做

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

您将获得异常的标头,而不是整个stacktrace。因为记录器会认为您正在传递字符串。不用{}像skaffman所说的那样做


1
当然,您将在此处获得整个堆栈的跟踪记录,但是{}也将逐字打印(不进行任何替换)?
k1eran 2015年

1
不要那么确定我的朋友!它对我不起作用,我只有标题。它可能取决于log4j的版本
iberbeu 2015年

@iberbeu是正确的,因为Throwable.toString()它不返回堆栈跟踪。(假设您使用的记录器知道如何处理'{}'。)

3

skaffman的答案绝对是正确的答案。所有记录方法,比如error()warn()info()debug()采取Throwable作为第二个参数:

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

但是,您也可以将stacktrace提取为String。有时,如果您希望利用“ {}”占位符来利用格式设置功能,则可能会很有用-请参见方法void info(String var1, Object... var2);在这种情况下,您将stacktrace作为String使用,那么您实际上可以执行以下操作:

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

这将在最后输出参数化的消息和stacktrace,方法与方法相同: logger.error("error: ", e);

我实际上写了一个开放源代码库,该库具有一个实用程序,可将String作为一个String提取出来,并带有一个选项,可以巧妙地从stacktrace中过滤掉一些噪音。即,如果您指定对提取的堆栈跟踪感兴趣的软件包前缀,则会从一些不相关的部分中过滤掉,并给您留下非常大的信息。这里是文章的链接,该文章解释了该库具有哪些实用程序以及在何处获取它(作为Maven工件和git源)以及如何使用它。带有堆栈跟踪过滤,静默字符串解析Unicode转换器和版本比较的开源Java库, 请参见“ Stacktrace噪声过滤器


一个掩埋但很好的答案。
payne

谢谢@payne。我很欣赏一个很好的反馈
迈克尔Gantman

2

该答案可能与提出的问题无关,但与问题的标题有关。

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

要么

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

要么

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

1

在Log4j 2中,可以使用Logger.catching()从捕获到的异常中记录堆栈跟踪

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

0

这将是很好的log4j错误/异常日志记录-splunk /其他日志记录/监视软件可以读取。一切都是键值对形式。log4j将从异常obj获取堆栈跟踪e

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


-1

您可以使用以下代码:

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


    }

}

您可以在这里致电: LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

它将把stackTrace打印到您的日志中。


-2

创建这个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);
        }
    };
}
}

在您的代码中调用

StdOutErrLog.tieSystemOutAndErrToLog();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.