log4j 不打印异常的堆栈跟踪
Posted
技术标签:
【中文标题】log4j 不打印异常的堆栈跟踪【英文标题】:log4j not printing the stacktrace for exceptions 【发布时间】:2011-01-18 16:43:04 【问题描述】:我正在将 log4j 与 tomcat 一起使用。当我在我的 JSP 中记录异常时,servlet:
private Logger _log = Logger.getLogger(this.getClass());
...
try... catch (Exception e)
_log.error("Error refreshing all prices", e);
我只得到异常的第一行,没有堆栈跟踪。
17-Feb 17:37:45 错误 AutoContrib:175 - 发布 csv 文件时出现异常: java.lang.ArrayIndexOutOfBoundsException
一点帮助都没有!
我的 log4j.properties 文件(/tomcat/common/classes/log4j.properties)如下所示:
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%ddd-MMM HH:mm:ss %5p %c1:%L - %m%n
log4j.appender.stdout.threshold=info
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.maxFileSize=5000KB
log4j.appender.file.maxBackupIndex=10
log4j.appender.file.File=$catalina.home/logs/web.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%ddd-MMM HH:mm:ss %5p %c1:%L - %m%n
log4j.appender.file.threshold=info
log4j.rootLogger=debug, stdout, file
【问题讨论】:
据我所知,您正在按照应有的方式进行操作...您应该在日志中看到所有堆栈跟踪。你用的是哪个版本的 log4j、Java 和 Tomcat? 我们使用的是 tomcat 5.5.17 和 log4j-1.2.14(我想我们会在不久的将来升级到 tc6,但我不确定这会有什么不同?)跨度> 您可以查看下面的帖子。它有完整的答案***.com/a/51655824/3073945 从最近关于 log4jShell 的新闻来看,这是我现在最不担心的事情了!... 【参考方案1】:实际上,可能是由于热点优化:在抛出一定数量的相同异常后,它会停止打印跟踪。这可以通过 VM arg 关闭,请参阅:
来自http://www.oracle.com/technetwork/java/javase/relnotes-139183.html:
服务器 VM 中的编译器现在提供正确的堆栈回溯 对于所有“冷”内置异常。出于性能目的,当 这样的异常被抛出几次,方法可能被重新编译。 重新编译后,编译器可能会选择使用更快的策略 不提供堆栈跟踪的预分配异常。禁用 完全使用预分配的异常,使用这个新标志: -XX:-OmitStackTraceInFastThrow。
更多:
http://jawspeak.com/2010/05/26/hotspot-caused-exceptions-to-lose-their-stack-traces-in-production-and-the-fix/
【讨论】:
为什么是Java...为什么...? 没有什么比用“java.lang.NullPointerException”在生产系统上敲打你的头并试图找出它在类中的位置的事情了。【参考方案2】:您发布的内容应显示javadoc 中所述的堆栈跟踪。
请注意,如果您不包含消息(仅调用 logger.error(ex)
),则不会记录堆栈跟踪。
【讨论】:
啊。它在那里。这就是咬我的东西。记录错误不会打印堆栈跟踪。您需要记录一条带有错误的消息才能得到它。 这很有帮助。谢谢你。我们能否配置 log4j,即使我们只提供异常对象,它也能显示完整的跟踪信息?【参考方案3】:错误方法有两种重载方法。
logger.error(ex);
logger.error("some oops string ", ex);
如果你使用第一种方法,它只会打印异常的名称。
如果您使用第二种方法,一些消息和异常将打印类似于e.printStackTrace()
方法的完整堆栈跟踪。
【讨论】:
【参考方案4】:就像上面@Luhar 的回答一样,我也在为同样的事情苦苦挣扎,最后这对我有用; 这种方法的好处是我们不必修改 JVM、Log4J 等系统级设置,因为我们永远不知道它可能会导致新的意外惊喜!
try
...
..
catch (Exception er)
ByteArrayOutputStream os = new ByteArrayOutputStream();
er.printStackTrace(new PrintStream(os));
LOGGER.error(new String(os.toByteArray()));
//LOGGER.error(er);
【讨论】:
【参考方案5】:我没有发现您的配置有任何问题,因此请尝试将log4j
升级到更新的(不一定是最新的)版本。
虽然在这种情况下不是问题,但你最好让你的记录器private static final
【讨论】:
【参考方案6】:我没有使用 fillStackTrace 调用,所以我无法评论它是否有效。另一种方法是使用一种从异常返回格式化文本的小方法。
public static String getStackTrace(Exception e)
StringWriter sWriter = new StringWriter();
PrintWriter pWriter = new PrintWriter(sWriter);
e.printStackTrace(pWriter);
return sWriter.toString();
在您的日志记录代码中,您可以编写:
logger.error("An exception occurred: " + Utils.getStackTrace(e));
【讨论】:
理想情况下,他不需要这个【参考方案7】:您可以在 catch 块中添加这些代码行。
catch (SQLException e)
CharArrayWriter cw = new CharArrayWriter();
PrintWriter w = new PrintWriter(cw);
e.printStackTrace(w);
w.close();
String trace = cw.toString();
log.error("This is complete stacktrace", trace);
【讨论】:
【参考方案8】:使用您的代码示例:
private static final Logger _log = Logger.getLogger(MyClass.class);
...
try... catch (Exception e)
//Change
//_log.error("Error refreshing all prices", e);
//To
_log.error("Error refreshing all prices", e.fillInStackTrace());
您将看到显示的所有堆栈跟踪。
PS。在声明 public class MyClass
之后将 Logger 设为单例...(查看我的声明)
【讨论】:
感谢您的建议!我现在就试试这个。顺便说一句,对于单例方法,您不能将“this”与静态 getLoggger() 一起使用。我想我可以使用 getLogger(MyClass.class) 真正的瑞恩!看到单例在创建后已经存在,它使实例化更快。 将堆栈跟踪更改为当前线程的状态。它不再是抛出异常的堆栈跟踪 线程的堆栈跟踪与异常的堆栈跟踪不同。异常的堆栈跟踪显示异常发生的位置,线程的堆栈跟踪(在这种情况下)显示异常被捕获的位置。 fillInStackTrace 没有记录原因 afaik,它(原因)是在创建异常时设置的(此时也调用了 fillInStackTrace)以上是关于log4j 不打印异常的堆栈跟踪的主要内容,如果未能解决你的问题,请参考以下文章
如何让 log4j syslog appender 在一行中写入堆栈跟踪?