2010-02-19 109 views
54

我使用的是tomcat的log4j。当我在JSP中记录异常时,servlets:log4j不打印例外的堆栈跟踪

private Logger _log = Logger.getLogger(this.getClass()); 
... 
try{...} catch (Exception e) { 
    _log.error("Error refreshing all prices", e); 
} 

我只得到异常的第一行,没有堆栈跟踪。

17月17时37分45秒ERROR 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 
+0

据我所见,你所做的一切都应该完成......你应该看到你的日志中的所有堆栈跟踪。你正在使用哪个版本的log4j,Java和Tomcat? – 2010-02-19 09:03:29

+0

我们使用的是tomcat 5.5.17和log4j-1.2.14(我想我们会在不久的将来升级到tc6,但我不确定这会有什么区别?) – Ryan 2010-02-19 09:05:37

回答

58

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

0

使用您的代码示例:

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 {

+0

感谢您的建议!我现在就试试这个。 顺便说一句,对于单例方法,您不能在静态getLoggger()中使用'this'。我想我可以使用getLogger(MyClass.class) – Ryan 2010-02-19 09:18:12

+0

True Ryan !.它使得实例化更快,看到单例在创建后已经存在。 – 2010-02-19 09:22:47

+0

理想情况下,他不需要这个 – Bozho 2010-02-20 10:49:11

0

我没有看到你的配置有什么问题,因此请尝试将log4j升级到更新版本(不一定是最新版本)。

虽然没有在这种情况下这个问题,你最好让你的伐木工人private static final

1

我没有用过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)); 
+0

理想情况下,他不应该需要这个 – Bozho 2010-02-20 10:48:41

15

你已经张贴什么应显示堆栈跟踪在javadoc说明。

请注意,如果您不包含消息(并且只需调用logger.error(ex)),那么不会记录堆栈跟踪。

+3

啊。它是。这就是咬我的东西。记录错误不会打印堆栈跟踪。您需要记录带有错误的消息才能获得该消息。 – rbwhitaker 2013-05-10 17:02:10

+0

这很有帮助。谢谢。我们可以配置log4j,因此即使我们只提供异常对象,它也会显示完整的跟踪信息吗? – 2017-03-31 13:38:43

3

像通过@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); 
} 
0

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

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

  1. logger.error(ex);
  2. logger.error("some oops string ", ex);
如果使用第1种方法

,这将只打印了异常的名称。 如果您使用第二种方法,一些消息以及异常将打印类似于e.printStackTrace()方法的完整堆栈跟踪。

+0

谢谢。我认为这是正确的答案。 – 2017-09-06 12:22:24