1. 程式人生 > >web專案中如何選擇日誌元件(SLF4J、Log4J2、logback)

web專案中如何選擇日誌元件(SLF4J、Log4J2、logback)

一:SLF4J、Log4J2、logback、Apache log4j元件簡介

  • slf4j譯為簡單日誌門面,是日誌框架的抽象。LogBack和Log4j都是開源日記工具庫,LogBack是Log4j的改良版本,比Log4j擁有更多的特性,同時也帶來很大效能提升。詳細資料可參照下面地址:Reasons to prefer logback over log4j
  • Log4j2Apache的一個開放原始碼專案,通過使用Log4j2,我們可以控制日誌資訊輸送的;我們也可以控制每一條日誌的輸出格式;通過定義每一條日誌資訊的級別,我們能夠更加細緻地控制日誌的生成過程。最令人感興趣的就是,這些可以通過一個配置檔案來靈活地進行配置,而不需要修改應用的程式碼。 Log4j1已經在2015年就宣佈涼了,在此就不做討論了。
    log4j
    2相對於Log4J1的優點:
    1. Log4j 2被設計為可以作為審計框架使用。Log4j 1.x和Logback都會在重新配置的時候失去事件,而Log4j2不會。在Logback中,Appender當中的異常對應用從來都是不可見的。但Log4j2的Appender可以設定為允許將異常滲透給應用程式。
    2. Log4j 2包含基於LMAX Disruptor庫的下一代非同步日誌器。在多執行緒情況下,非同步日誌器具有比Log4j 1.x和Logback高出10倍的吞吐效能以及更低的延遲。
    3. Log4j 2在穩定記錄狀態下,對單機應用是無垃圾的,對Web應用是低垃圾的。這不僅降低了垃圾回收器的壓力,還可以提供更好的響應效能。
    4. Log4j 2使用外掛系統使得它非常容易通過新的Appender、Filter、Layout、Lookup和Pattern Converter來擴充套件框架,且不需要對Log4j做任何修改。
    5. 由於外掛系統的配置更簡單了,配置項不需要宣告類名稱。
    6. 支援自定義日誌級別。自定義日誌級別可以在程式碼或配置中定義。
    7. 支援Lambda表示式。執行在Java 8上的客戶端程式碼可以使用Lambda表示式來實現僅在對應的日誌級別啟用時延遲構造日誌訊息。由於不需要明確地層層把關,這帶來了更簡潔的程式碼。
    8. 支援Message物件。Message允許支援感興趣或複雜的結構體在日誌系統中傳輸,且可以被高效地操作。使用者可以自由地建立他們自己的Message型別,並編寫自定義的Layout、Filter和Lookup來操作它們。
    9. Log4j 1.x支援Appender上的Filter。Logback引入了TurboFilter來在事件被Logger處理之前對它們進行過濾。Log4j 2支援的Filter可以設定為在被Logger接管之前即處理事件,如同它在Logger或Appender中被處理。
    10. 很多Logback的Appender不接受一個Layout,且只能傳送固定格式的資料。而大多數Log4j 2的Appender接受Layout,允許資料以任意一種所需的格式傳輸。
    11. Log4j 1.x和Logback中的Layout返回一個String。這導致了在Logback Encoder中討論的問題。Log4j 2用更簡單的方法,Layout總是返回一個位元組陣列。優點是這意味著它們可以用於任何Appender,而不僅僅是寫入到OutputStream中的那些。
    12. Syslog Appender既支援TCP也支援UDP,同樣支援BSD系統日誌以及RFC 5424格式。
    13. Log4j 2利用了Java 5的併發優勢,並在儘可能最低的程度上進行鎖定。Log4j 1.x中已知存在死鎖問題。其中很多已經在Logback中修復,但很多Logback的class檔案仍然需要在更高的編譯級別中同步。
    14. 這是一個被所有ASF專案集體支援使用的Apache軟體基金會專案。如果你想要貢獻或修改,只要參照貢獻中的方法。
  • logback同樣是由log4j的作者設計完成的,擁有更好的特性,用來取代log4j的一個日誌框架。是slf4j的原生實現。(Native implementations)
  • Slf4j是The Simple Logging Facade for Java的簡稱,是一個簡單日誌門面抽象框架,它本身只提供了日誌Facade API和一個簡單的日誌類實現,一般常配合Log4j,LogBack,java.util.logging使用。Slf4j作為應用層的Log接入時,程式可以根據實際應用場景動態調整底層的日誌實現框架(Log4j/LogBack/JdkLog...);

二:為什麼要SLF4J與其他元件結合使用?

    為什麼使用SLF4J與其他元件結合使用比單獨使用log4j2或者java.util.logging要優秀呢。

    SLF4J不同於其他日誌類庫,與其它有很大的不同。SLF4J(Simple logging Facade for Java)不是一個真正的日誌實現,而是一個抽象層( abstraction layer),它允許你在後臺使用任意一個日誌類庫。如果是在編寫供內外部都可以使用的API或者通用類庫,那麼你真不會希望使用你類庫的客戶端必須使用你選擇的日誌類庫。

    如果一個專案已經使用了log4j2,而你載入了一個類庫,比方說 Apache Active MQ——它依賴於於另外一個日誌類庫logback,那麼你就需要把它也載入進去。但如果Apache Active MQ使用了SLF4J,你可以繼續使用你的日誌類庫而無語忍受載入和維護一個新的日誌框架的痛苦。

    總的來說,SLF4J使你的程式碼獨立於任意一個特定的日誌API,這是一個對於開發API的開發者很好的思想。雖然抽象日誌類庫的思想已經不是新鮮的事物而且Apache commons logging也已經在使用這種思想了,但現在SLF4J正迅速成為Java世界的日誌標準。讓我們再看看幾個使用SLF4J而不是log4j2、logback或者java.util.logging的理由。

    SLF4J對比Log4J2,logback和java.util.Logging的優勢

    正如我之前說的,在你的程式碼中使用SLF4J寫日誌語句的主要出發點是使得你的程式獨立於任意特定的日誌類庫,依賴於特定類可能需要不同與你已有的配置,並且導致更多維護的麻煩。但除此之外,還要一個SLF4J API的特性使得我堅持使用SLF4J而拋棄我長期間鍾愛的Lof4j的理由,是被稱為佔位符(place holder),在程式碼中表示為“{}”的特性。佔位符是一個非常類似於在String的format()方法中的%s,因為它會在執行時被某個提供的實際字串所替換。這不僅降低了你程式碼中字串連線次數,而且還節省了新建的String物件。即使你可能沒需要那些物件,但這個依舊成立,取決於你的生產環境的日誌級別,例如在DEBUG或者INFO級別的字串連線。因為String物件是不可修改的並且它們建立在一個String池中,它們消耗堆記憶體( heap memory)而且大多數時間他們是不被需要的,例如當你的應用程式在生產環境以ERROR級別執行時候,一個String使用在DEBUG語句就是不被需要的。通過使用SLF4J,你可以在執行時延遲字串的建立,這意味著只有需要的String物件才被建立。而如果你已經使用log4j,那麼你已經對於在if條件中使用debug語句這種變通方案十分熟悉了,但SLF4J的佔位符就比這個好用得多。

    這是你在Log4j中使用的方案,但肯定這一點都不有趣並且降低了程式碼可讀性因為增加了不必要的繁瑣重複程式碼(boiler-plate code):

123if (logger.isDebugEnabled()) {logger.debug("Processing trade with id: " + id + " symbol: " + symbol);}

    另一方面,如果你使用SLF4J的話,你可以得到在極簡潔的格式的結果,就像以下展示的一樣:

1logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);

    在SLF4J,我們不需要字串連線而且不會導致暫時不需要的字串消耗。取而代之的,我們在一個以佔位符和以引數傳遞實際值的模板格式下寫日誌資訊。你可能會在想萬一我有很個引數怎麼辦?嗯,那麼你可以選擇使用變數引數版本的日誌方法或者用以Object陣列傳遞。這是一個相當的方便和高效方法的打日誌方法。記住,在生產最終日誌資訊的字串之前,這個方法會檢查一個特定的日誌級別是不是打開了,這不僅降低了記憶體消耗而且預先降低了CPU去處理字串連線命令的時間。這裡是使用SLF4J日誌方法的程式碼,來自於slf4j-log4j12-1.6.1.jar中的Log4j的介面卡類Log4jLoggerAdapter。

123456public void debug(String format, Object arg1, Object arg2) {if (logger.isDebugEnabled()) {FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());}}

    同時,我們也很值得知道打日誌是對應用程式的效能有著很大影響的,在生產環節上只進行必要的日誌記錄是我們所建議的。

    上面介紹了SLF4J的優點與好處 ,當我們使用該元件時,我們可以結合其他元件進行使用,推薦使用LogBack或者Log4J2,因為LogBack和Log4J2是Log4j的改良版本,比Log4j擁有更多的特性,同時也帶來很大效能提升。

    總結

    總結這次說的,我建議使用SLF4J的而不是直接使用 LogBack,Log4J2, commons logging, logback 或者 java.util.logging 已經足夠充分了。

  1. 在你的開源或內部類庫中使用SLF4J會使得它獨立於任何一個特定的日誌實現,這意味著不需要管理多個日誌配置或者多個日誌類庫,你的客戶端會很感激這點。
  2. SLF4J提供了基於佔位符的日誌方法,這通過去除檢查isDebugEnabled(), isInfoEnabled()等等,提高了程式碼可讀性。
  3. 通過使用SLF4J的日誌方法,你可以延遲構建日誌資訊(Srting)的開銷,直到你真正需要,這對於記憶體和CPU都是高效的。
  4. 作為附註,更少的暫時的字串意味著垃圾回收器(Garbage Collector)需要做更好的工作,這意味著你的應用程式有為更好的吞吐量和效能。(此部分內容詳細請了解JVM的垃圾回收機制)
  5. 這些好處只是冰山一角,你將在開始使用SL4J和閱讀其中程式碼的時候知道更多的好處。我強烈建議,任何一個新的Java程式設計師,都應該使用SLF4J做日誌而不是使用包括Log4J在內的其他日誌API。
  6. ps:不要再用Log4J1了,有更好的元件讓我們使用,何樂而不為呢,=.=
參考文章: javarevisited 翻譯: ImportNew.com - Jaskey     http://www.importnew.com/7450.html