2010-12-03 161 views
130

說你捕獲異常,並得到在標準輸出下面的(比如說,控制檯),如果你做一個e.printStackTrace()如何發送堆棧跟蹤到log4j?

java.io.FileNotFoundException: so.txt 
     at java.io.FileInputStream.<init>(FileInputStream.java) 
     at ExTest.readMyFile(ExTest.java:19) 
     at ExTest.main(ExTest.java:7) 

現在,我想送這個來代替公司,比如,log4j的一個記錄器,以獲得以下內容:

31947 [AWT-EventQueue-0] ERROR Java.io.FileNotFoundException: so.txt 
32204 [AWT-EventQueue-0] ERROR at java.io.FileInputStream.<init>(FileInputStream.java) 
32235 [AWT-EventQueue-0] ERROR at ExTest.readMyFile(ExTest.java:19) 
32370 [AWT-EventQueue-0] ERROR at ExTest.main(ExTest.java:7) 

我怎樣才能做到這一點?

try { 
    ... 
} catch (Exception e) { 
    final String s; 
    ... // <-- What goes here? 
    log.error(s); 
} 

回答

218

您將異常直接傳遞給記錄器,例如,

try { 
    ... 
} catch (Exception e) { 
    log.error("failed!", e); 
} 

這取決於log4j呈現堆棧跟蹤。

+24

記錄器接受一個對象爲它的第一個參數,將的toString()它。但是第二個參數必須是Throwable並顯示堆棧跟蹤。 – 2010-12-03 16:50:20

+1

我從來不知道什麼東西進入第一個String,通常我只落得做`log.error(e.getLocalizedMessage(),E)`這完全是多餘的。它是否爲第一個參數處理空值? – 2010-12-03 16:52:11

+4

@Mark:試着給它一個比例外消息更適合上下文的消息,例如:那時它究竟在做什麼? – skaffman 2010-12-03 16:53:37

6

您還可以通過ExceptionUtils.getStackTrace以字符串形式獲取堆棧跟蹤。

參見:ExceptionUtils.java

我僅使用它log.debug,保持log.error簡單。

-2

創建此class:在你的代碼

StdOutErrLog.tieSystemOutAndErrToLog(); 
2

這個答案可能不相關的問這個問題,但相關的問題的標題

public class StdOutErrLog { 

private static final Logger logger = Logger.getLogger(StdOutErrLog.class); 

public static void tieSystemOutAndErrToLog() { 
    System.setOut(createLoggingProxy(System.out)); 
    System.setErr(createLoggingProxy(System.err)); 
} 

public static PrintStream createLoggingProxy(final PrintStream realPrintStream) { 
    return new PrintStream(realPrintStream) { 
     public void print(final String string) { 
      logger.info(string); 
     } 
     public void println(final String string) { 
      logger.info(string); 
     } 
    }; 
} 
} 

調用此。

public class ThrowableTest { 

    public static void main(String[] args) { 

     Throwable createdBy = new Throwable("Created at main()"); 
     ByteArrayOutputStream os = new ByteArrayOutputStream(); 
     PrintWriter pw = new PrintWriter(os); 
     createdBy.printStackTrace(pw); 
     try { 
      pw.close(); 
      os.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     logger.debug(os.toString()); 
    } 
} 

OR

public static String getStackTrace (Throwable t) 
{ 
    StringWriter stringWriter = new StringWriter(); 
    PrintWriter printWriter = new PrintWriter(stringWriter); 
    t.printStackTrace(printWriter); 
    printWriter.close(); //surprise no IO exception here 
    try { 
     stringWriter.close(); 
    } 
    catch (IOException e) { 
    } 
    return stringWriter.toString(); 
} 

OR

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); 
for(StackTraceElement stackTrace: stackTraceElements){ 
    logger.debug(stackTrace.getClassName()+ " "+ stackTrace.getMethodName()+" "+stackTrace.getLineNumber()); 
} 
1

只是因爲它發生在我身上,可以是有用的。 如果你這樣做

try { 
    ... 
} catch (Exception e) { 
    log.error("failed! {}", e); 
} 

你會得到異常的頭部,而不是整個堆棧跟蹤。因爲記錄器會認爲你傳遞了一個字符串。 做沒有{}爲skaffman說

7

如果你想記錄一個堆棧跟蹤不涉及例外只是這樣做:

String message = ""; 

for(StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {       
    message = message + System.lineSeparator() + stackTraceElement.toString(); 
} 
log.warn("Something weird happened. I will print the the complete stacktrace even if we have no exception just to help you find the cause" + message); 
0

從skaffman答案肯定是正確的答案。所有記錄的方法,如error()warn()info()debug()採取Throwable作爲第二個參數:

try { 
... 
} catch (Exception e) { 
logger.error("error: ", e); 
} 

但是,您可以提取堆棧跟蹤的字符串爲好。有時候,如果你想採取格式化使用功能的優勢可能是有用的「{}」佔位符 - 參見方法void info(String var1, Object... var2);在這種情況下,說你有一個堆棧跟蹤字符串,那麼實際上你可以做這樣的事情:

try { 
... 
} catch (Exception e) { 
String stacktrace = TextUtils.getStacktrace(e); 
logger.error("error occurred for usename {} and group {}, details: {}",username, group, stacktrace); 
} 

這將打印參數化的消息和堆棧跟蹤在結束它的方法是相同的:logger.error("error: ", e);

其實,我寫了有一個堆棧跟蹤作爲一個字符串的提取工具的選項巧妙地過濾的開源庫從堆棧中抽出一些噪音。即如果你指定你感興趣的軟件包前綴,那麼你的解壓棧跟蹤將被過濾掉一些不相關的部分,並給你提供非常有用的信息。這篇文章的鏈接解釋了這個庫有哪些實用工具,以及在哪裏可以獲得它(既作爲maven工件也作爲git源代碼)以及如何使用它。 Open Source Java library with stack trace filtering, Silent String parsing Unicode converter and Version comparison查看段落「堆棧跟蹤噪聲濾波器

0

這將是很好的log4j錯誤/異常日誌記錄 - 通過的Splunk /其他日誌/監視S/W可讀。一切都是鍵值對的形式。 的log4j將從異常獲得堆棧跟蹤物鏡e

try { 
      --- 
      --- 
    } catch (Exception e) { 
     log.error("api_name={} method={} _message=\"error description.\" msg={}", 
        new Object[]{"api_name", "method_name", e.getMessage(), e}); 
    } 
0
Try this: 

catch (Throwable t) { 
    logger.error("any message" + t); 
    StackTraceElement[] s = t.getStackTrace(); 
    for(StackTraceElement e : s){ 
     logger.error("\tat " + e); 
    } 
}