log4j不打印异常的堆栈跟踪


70

我在tomcat中使用log4j。当我在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=%d{dd-MMM HH:mm:ss} %5p %c{1}:%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=%d{dd-MMM HH:mm:ss} %5p %c{1}:%L - %m%n
log4j.appender.file.threshold=info

log4j.rootLogger=debug, stdout, file

据我所知,您正在做所有应做的事情……您应该在日志中看到所有的stacktrace。您正在使用哪个版本的log4j,Java和Tomcat?
Manrico Corazzi

我们正在使用tomcat 5.5.17和log4j-1.2.14(我认为我们会在不久的将来升级到tc6,但我不确定这会有什么不同吗?)
Ryan

您可以查看波纹管螺纹。它有完整的答案stackoverflow.com/a/51655824/3073945
Sajedul Karim博士

Answers:


90

实际上,这可能是由于热点优化所致:在抛出一定数量的相同异常后,它将停止打印跟踪。可以使用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/


5
为什么是Java ...为什么...?
JTW

23

您发布的内容应显示javadoc中所述的堆栈跟踪。

请注意,如果不包括消息(仅调用logger.error(ex)),则不会记录堆栈跟踪。


3
啊。在那里。这就是在咬我。记录错误不会打印堆栈跟踪。您需要记录一条错误消息以获取该信息。
rbwhitaker

这很有帮助。谢谢。我们是否可以配置log4j以便即使我们仅提供异常对象也可以显示完整的跟踪记录?
查尔斯·莫林

20

错误方法有两种重载方法。

  1. logger.error(ex);
  2. logger.error("some oops string ", ex);

如果您使用1st方法,则只会打印Exception的名称。如果您使用第二种方法,则某些消息以及异常将打印与e.printStackTrace()方法类似的完整堆栈跟踪 。


这是我的情况。谢谢!
frankieta

7

就像上面@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);
}

1

我的配置没有发现任何问题,请尝试升级 log4j到较新的版本(不一定是最新版本)。

尽管在这种情况下不是问题,但最好使记录器 private static final


1

我还没有使用fillStackTrace调用,所以我无法发表评论。另一种方法是使用一点方法,该方法从Exception返回格式化的文本。

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

理想情况下,他不需要这个
Bozho 2010年

1

您可以在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);
}

-1

使用您的代码示例:

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。在声明之后,将Logger设为单身...(检查我的声明)public class MyClass {


感谢您的建议!我现在将尝试。顺便说一句,对于单例方法,您不能在静态getLoggger()中使用“ this”。我想我可以使用getLogger(MyClass.class)
瑞安

真正的瑞安!看到单例创建后已经存在,可以使实例化更快。
Buhake Sindi

4
将堆栈跟踪更改为当前线程的状态。它将不再是引发异常的堆栈跟踪
对象

2
线程的堆栈跟踪与异常的堆栈跟踪不同。异常的堆栈跟踪显示发生异常的位置,线程的堆栈跟踪(在本例中)显示捕获异常的位置。
对象

1
fillInStackTrace不记录原因afaik,它在创建异常时设置(原因)(此时也调用fillInStackTrace)
对象
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.