2010-02-19 111 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