如何向 log4j 发送堆栈跟踪?

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

现在我想把它发送给一个 logger,比如 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 );
}
160388 次浏览

将异常直接传递给日志记录器,例如。

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

由 log4j 呈现堆栈跟踪。

您还可以通过 ExceptionUtils.getStackTrace获得作为字符串的堆栈跟踪。

见: ExceptionUtils.java

我只对 log.debug使用它,以保持 log.error的简单。

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

这个答案可能与所问的问题无关,而是与问题的题目有关。

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

只是因为它发生在我身上,可以有用。 如果你这么做

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

您将获得异常的头部,而不是整个堆栈跟踪。因为日志记录器会认为您正在传递一个 String。 就像斯卡夫曼说的,不要用 {}

如果您想在不涉及异常的情况下记录堆栈跟踪,只需要这样做:

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

斯卡夫曼的回答绝对是正确的。所有日志记录器方法(如 error()warn()info()debug())都将 Throwable 作为第二个参数:

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

但是,您也可以将堆栈跟踪提取为 String。如果你想利用“{}”占位符格式化特性的优势,有时候它会很有用——参见方法 void info(String var1, Object... var2);在这种情况下,假设你有一个作为 String 的堆栈跟踪,那么你实际上可以这样做:

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

这将以与方法 logger.error("error: ", e);相同的方式在末尾打印参数化消息和堆栈跟踪

我实际上编写了一个开源库,它有一个用于提取作为字符串的堆栈跟踪的实用程序,还有一个从堆栈跟踪中聪明地过滤掉一些噪音的选项。例如,如果您指定的包前缀,您感兴趣的提取堆栈跟踪将过滤出一些不相关的部分,并留给您非常细致的信息。下面是这篇文章的链接,它解释了库所拥有的实用程序以及从哪里获取它(作为 maven 工件和 git 源)以及如何使用它。见段落“ 堆栈跟踪噪声滤波器

这将是一个很好的 log4j 错误/异常日志记录-可以通过 splunk/other 日志记录/监视 s/w 进行读取。 Log4j 将从 Exception obj e获取堆栈跟踪

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


catch (Throwable t) {
logger.error("any message" + t);
StackTraceElement[] s = t.getStackTrace();
for(StackTraceElement e : s){
logger.error("\tat " + e);
}
}

你可以使用以下代码:

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 打印到您的日志中。

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

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