如何将堆栈跟踪发送到 log4j?
Posted
技术标签:
【中文标题】如何将堆栈跟踪发送到 log4j?【英文标题】:How to send a stacktrace to log4j? 【发布时间】:2011-05-19 20:49:33 【问题描述】:假设你捕获了一个异常并在标准输出(比如控制台)上得到以下信息,如果你执行 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 );
【问题讨论】:
【参考方案1】:您将异常直接传递给记录器,例如
try
...
catch (Exception e)
log.error( "failed!", e );
由 log4j 来呈现堆栈跟踪。
【讨论】:
记录器将一个对象作为它的第一个参数,并将 toString() 它。但是第二个参数必须是 Throwable 并显示堆栈跟踪。 我永远不知道在第一个字符串中填充什么,通常我最终会做log.error(e.getLocalizedMessage(), e)
,这完全是多余的。它是否处理第一个参数的空值?
@Mark:尝试给它一个比异常消息更贴近上下文的消息,例如当时它到底想做什么?
@Mark Peters,一个很好的例子是将当前方法的参数记录为消息,或者 - 对于 FileNotFound 异常,尝试打开的路径的全名。任何可以帮助您找出问题所在的方法——只要认为您无法调试情况即可。
@skaffman:实际上我正在使用log4j-1.2.8.jar
,我想在我的日志文件上打印所有stackTrace
,所以我尝试像上面提到的那样,但只是在我的日志文件上打印nullPointerException
.我在我的代码e.printStackTrace()
上使用它打印所有跟踪。为什么是这个 Kolavery?【参考方案2】:
您还可以通过ExceptionUtils.getStackTrace
以字符串形式获取堆栈跟踪。
见:ExceptionUtils.java
我只将它用于log.debug
,以保持log.error
简单。
【讨论】:
【参考方案3】:创建这个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();
【讨论】:
【参考方案4】:此答案可能与提出的问题无关,但与问题的标题有关。
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());
【讨论】:
【参考方案5】:只是因为它发生在我身上并且可能有用。 如果你这样做
try
...
catch (Exception e)
log.error( "failed! ", e );
您将获得异常的标头,而不是整个堆栈跟踪。因为记录器会认为您正在传递一个字符串。
正如 skaffman 所说,不用 就可以了
【讨论】:
您肯定会在这里获得整个堆栈跟踪,但是 也会逐字打印(没有任何替换)? 别那么肯定我的朋友!这对我不起作用,我只有标题。它可能取决于 log4j 的版本 @iberbeu 是正确的,因为Throwable.toString()
不返回堆栈跟踪。 (假设您使用的记录器知道如何处理“”。)【参考方案6】:
如果您想在不涉及异常的情况下记录堆栈跟踪,只需执行以下操作:
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);
【讨论】:
System.lineSeparator() 的 +1,这帮助我打印了一个堆栈跟踪,这是我从远程服务获得的响应 我搜索过的,但你应该在这里使用 StringBuilder【参考方案7】:skaffman 的答案绝对是正确的答案。 error()
、warn()
、info()
、debug()
等所有 logger 方法都将 Throwable 作为第二个参数:
try
...
catch (Exception e)
logger.error("error: ", e);
但是,您也可以将堆栈跟踪提取为字符串。有时,如果您希望使用“”占位符来利用格式化功能,这可能会很有用 - 请参阅方法 void info(String var1, Object... var2);
在这种情况下,假设您有一个堆栈跟踪作为字符串,那么您实际上可以执行以下操作:
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);
实际上,我编写了一个开源库,其中包含一个实用程序,用于将堆栈跟踪提取为字符串,并且可以选择巧妙地从堆栈跟踪中过滤掉一些噪音。 IE。如果您指定您对提取的堆栈跟踪感兴趣的包前缀,则会从一些不相关的部分中过滤掉,并为您留下非常简洁的信息。这是文章的链接,该链接解释了该库具有哪些实用程序以及从何处获取它(作为 maven 工件和 git 源)以及如何使用它。 Open Source Java library with stack trace filtering, Silent String parsing Unicode converter and Version comparison 见段落“Stacktrace 噪声过滤器”
【讨论】:
一个隐藏但很好的答案。 谢谢,@payne。非常感谢您的反馈 谢谢。我最终提出了这个问题,因为我一直在寻找这个答案。 @axiopisty - 欢迎您。我很高兴它对你有用【参考方案8】:这将是很好的 log4j 错误/异常日志记录 - 可由 splunk/其他日志记录/监控软件读取。一切都是键值对的形式。
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);
【讨论】:
【参考方案9】:Try this:
catch (Throwable t)
logger.error("any message" + t);
StackTraceElement[] s = t.getStackTrace();
for(StackTraceElement e : s)
logger.error("\tat " + e);
【讨论】:
【参考方案10】:您可以使用以下代码:
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 打印到您的日志中。
【讨论】:
【参考方案11】:在 Log4j 2 中,您可以使用 Logger.catching() 从捕获的异常中记录堆栈跟踪。
try
String msg = messages[messages.length];
logger.error("An exception should have been thrown");
catch (Exception ex)
logger.catching(ex);
【讨论】:
您也可以毫无例外地打印堆栈跟踪,使用:logger.catching(new Throwable());
以上是关于如何将堆栈跟踪发送到 log4j?的主要内容,如果未能解决你的问题,请参考以下文章
如何让 log4j syslog appender 在一行中写入堆栈跟踪?