【问题标题】:log4j not printing the stacktrace for exceptionslog4j 不打印异常的堆栈跟踪
【发布时间】: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=%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

【问题讨论】:

  • 据我所知,您正在按照应有的方式进行操作...您应该在日志中看到所有堆栈跟踪。你用的是哪个版本的 log4j、Java 和 Tomcat?
  • 我们使用的是 tomcat 5.5.17 和 log4j-1.2.14(我想我们会在不久的将来升级到 tc6,但我不确定这会有什么不同?)跨度>
  • 您可以查看下面的帖子。它有完整的答案stackoverflow.com/a/51655824/3073945
  • 从最近关于 log4jShell 的新闻来看,这是我现在最不担心的事情了!...

标签: java tomcat logging log4j


【解决方案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】:

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

  1. logger.error(ex);
  2. 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)
          猜你喜欢
          • 2010-09-25
          • 1970-01-01
          • 1970-01-01
          • 2012-09-04
          • 2010-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多