2009-02-19 80 views
22

我想要一個由多個管理數據任務產生的診斷日誌。這些任務可能在多個線程中。每個任務都需要將一個元素(可能包含子元素)寫入日誌;快速出入。如果這是一項單一任務的情況,我會使用XMLStreamWriter,因爲它似乎是簡單/功能的最佳搭配,無需在內存中保留膨脹的XML文檔。從多個線程進行Java日誌記錄的最佳實踐?

但這不是一個單一任務的情況,我不確定如何最好地確保這是「線程安全」,其中應用程序中的「線程安全」意味着每個日誌元素應該正確寫入日誌並且串行(一個接一個,不以任何方式交錯)。

有什麼建議嗎?我有一種模糊的直覺認爲,要走的路是使用一個日誌元素隊列(每個元素都能夠快速生成:我的應用程序忙於做對性能敏感的實際工作),並且有一個單獨的線程來處理日誌元素並將它們發送到一個文件,這樣記錄不會中斷生產者。

日誌記錄不一定是XML,但我希望它是結構化和機器可讀的。

編輯:我把「threadsafe」放在引號中。 Log4j似乎是明顯的選擇(對我來說是新的,但對社區來說很老),爲什麼要重新發明輪子...

+0

我有同樣的問題,但不需要實時顯示日誌(只有在所有線程執行後)。我的解決方案是在每封郵件的開始處添加一個系統時間,並按時分類。 – Fuhrmanator 2013-04-13 21:56:15

+0

系統時間畢竟不可靠 - 有些操作非常接近,以至於它們具有相同的時間戳(以毫秒爲單位)。排序會導致訂單更改。所以,我嘗試的另一件事是使用Colllections.synchronizedList()來包裝消息字符串的ArrayList。添加到字符串的時間戳顯示,即使這樣做並不完美。在我的情況下,一些消息出現故障(一兩毫秒),但這可能是由於對同步列表的add()調用的排隊延遲。 – Fuhrmanator 2013-04-13 22:44:30

回答

21

使用日誌框架,如Log4j

+0

謝謝!現在閱讀文檔(http://logging.apache.org/log4j/1.2/manual.html)... – 2009-02-19 15:47:20

+2

確保在log4j ConversionPattern中使用'%t'表達式來記錄線程名稱 – chburd 2009-02-19 15:48:17

+3

我不認爲log4j使日誌線程安全。通過線程安全我的意思是記錄打印的順序必須與調度程序的任何順序相同。我相信你仍然需要使用同步和鎖定來記錄線程安全。 任何人想確認/否認? – jbu 2009-05-28 18:22:01

3

您可以使用同步機制(如監視器或信號燈)來確保在接受下一個日誌請求之前處理了一個日誌請求。這些都可以從調用日誌例程的代碼中隱藏起來。

4

使用日誌框架,如Log4。

如果你對輸出不滿意,你可以編寫你自己的Appender,Filter,無論它調整它只是寫。所以你甚至可以做一些緩存來重新排列條目,但我並不是說這是一個好主意。

3

log4j是和多年來一直是java日誌的標準。但是如果你不喜歡外部依賴,那麼java.util.logging包提供了一個可接受的解決方案。

0

自己以線程安全的方式開發這件事並不是微不足道的,所以您應該真正使用線程安全的現有日誌記錄框架。最常用的是Log4J,它是線程安全的(請參閱FAQ)。

20

我覺得你走錯了路。你說「線程安全」,但你的意思是「序列化」。線程安全意味着一個線程不會干擾來自其他線程的數據。大多數情況下,事先解決線程問題,您不應該爲了記錄而擔心。例如,如果你寫:

myVariableSum = 0 + myVariable; 
//here comes other thread - Not very likely! 
logger.info("Log some INFO; myVariable has value" + myVariable.toString()); 

你必須確保MYVARIABLE尚未從矩計算(第一行)其他線程改變進行,但測井方法之前被調用。如果發生這種情況,您將記錄不是用於執行操作的髒值,而是由其他某個線程分配的值。這通常被照顧;例如本地(方法級別)變量不能被其他線程改變。無論如何,如果您在登錄時不得不擔心這一點,那麼99%以上的程序已經存在嚴重的線程問題。
所有主要的日誌框架本身都是「線程安全的」,這意味着它們可以部署在多線程環境中,並且不會顯示類似於上面描述的內部問題。
獲取跟蹤記錄的順序通常稱爲調用的「序列化」。序列化日誌寫入將是任何多線程應用程序的主要性能瓶頸。如果您使用日誌框架(如log4j),則所有線程的跟蹤都會顯示在一個地方,或多或少地出現。但是,一列通常是線程名稱,因此您可以通過線程輕鬆過濾日誌數據;每個線程將按時間順序記錄其數據。看看這個鏈接: http://logging.apache.org/log4j/1.2/faq.html#1.7
最後,如果序列化日誌寫入是您真正需要的,那麼您可以使用某種結構,如java.util.concurrent.BlockingQueue來路由您的消息。

5

我傾向於在Log4J上面使用SLF4J。如果您要在生產環境中關閉很多日誌記錄語句,則parameterized logging功能尤其具有吸引力。

它也可以運行在java.util.logging的頂部或使用它自己的簡單輸出。

9

使用logback-classic。這是log4j的更新和更好的實現。

0

如果你不得不,你可以推出自己的..使用單寫入器/單讀卡器FIFO或隊列。

1

我對於特殊日誌只有類似的問題和實現需求。我的解決辦法是:

  1. 我花了blockinglinkedqueue與應用程序的流量/分鐘的*2大小。

  2. 所有線程將對象放入隊列並完成作業。

  3. 單獨Log-Writer線程從隊列中取出頭對象,並使用單獨的appender將其寫入log4j文件。這個appender沒有用於系統日誌。

這可以確保日誌連續寫入,並始終保持順序。

這不會影響應用程序的性能,因爲日誌寫入是一個完全獨立的過程,不會造成瓶頸。

您還可以使用log4jaysncappender