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打印错误异常的详细堆栈信息

手机调试Android程序出异常时不打印堆栈信息

如何让 log4j syslog appender 在一行中写入堆栈跟踪?

细读源码之Log4j打印异常堆栈导致线程Block问题分析

如何打印 C++ 中捕获的异常的堆栈跟踪和 C++ 中的代码注入

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