(9) Java Logging 的歷史與戰爭

Albert Hg
learning-from-jhipster
10 min readSep 30, 2020

Print Log、寫 Log 非常重要,在系統發生錯誤的時候要找到問題在哪裡,這時我們就得好好地追查 Log 有哪些錯誤訊息。或者是在開發的時候,要確保開發的功能沒有問題,也常常會需要透過 Log 來印出結果。

當你踏入了 Java 的領域,那就勢必得好好認識一下這五花八門的 Logging 的世界。為什麼說 Logging 的世界五花八門呢,沒錯,這根本就是 Java 界的戰爭,誰也不讓誰,那我們就開始從最源頭的部分開始說起吧。

Logging Framework 發展前

在還沒有 Logging 這個東西出現前,Java 的開發人員常常是使用最陽春的方法來印出值,也就是「System.out」與「System.err」,可是這樣印出 Log 的方法不夠彈性,也就只能將全部的 Log 都印出來,也不能處理不同錯誤級別的 Log。

Log4j (2001)

在1996年時,歐洲有一間企業(歐洲安全電子市場) The E.U. SEMPER 決定要紀錄自己的 API 行為,以方便追朔問題所在(參考1)(參考2)。

此時有一群人提出了 分層式的Logging (也就是可以將 Log 依照不同的級別選擇是否印出),個別是 N. AsokanCeki Gülcü 以及 Michael Steiner。最後由 Ceki Gülcü 等人開發了第一個 Logging Framework,Log4j。

大約在 2001 年左右,Ceki Gülcü 公開了 Log4j,接著 Log4j 加入了Apache 基金會的項目(當然 Ceki Gülcü 也加入了 Apache),也因此 Log4j 開始被大量使用並開始爆紅。

Java Util Logging ─ JUL (2002/02)

你可能會覺得奇怪,甲骨文收購的 Sun 既沒有自己的 Logging 系統,那幹嘛不將 Log4j 加入於 Java Util 內。

Sun 可能也是有自己的堅持,而且可能也已經有打算要在自己的 Util 內加入自己的 Logging ,果不其然的在 2002 的 2 月,發布了 Java 1.4,裡面就包含了自己的 Logging,JUL。

可是既然是戰爭,出兵出的晚,大多都是別人更勝一籌。Log4j 因為已經廣泛的被使用,所以也持續的有在進步,因此在效能上,當然 Log4j 會更佔上風。(題外話:JUL出來的晚,但效能或功能卻都不如Log4j)

Jakarta Commons Logging ─ JCL (2002/08)

對於原生 Java 來說,第三方 Log4j 固然好用,但總有人離不開原生,當 JUL 出現時,這就意味著客源會被吸走啊!

不過 Apache 也不是省油的燈,想說:「好,那我就出一個 Interface,讓使用者可以方便的使用在 Log4j 與 JUL 之間切換,這樣就可以讓大家都知道 Log4j 的好!」(內心戲很多)

Apache 新出的 Interface 就是 JCL。因此這時候,就有一個 Interface、兩個 Logging 框架。

Simple Logging Facade for Java ─ Slf4j (2005)

(這個小節內提到的內容,可以看 SLF4J News 的 Release 紀錄)

在 JCL 出現後,Log4j 的作者 Ceki Gülcü 覺得 JCL 的 API 實作方式不好,若使用者沒有照著規範走,那麼會引發效能問題。

例如一個避免引發效能問題的用法如下:

if (logger.isDebugEnabled()) {
  logger.debug("The value is : " + val);
}

如果你沒有先判別 isDebugEnabled(),那麼當透過 JCL 的 Interface 在處理這段 Log 時,縱使若 Logging 的等級比 Debug 還要高,卻依然還是會處理其中的字串,進而導致效能沒有最佳化的問題。

不過老實說,這其實也是 Ceki Gülcü 在開發 Log4j 時留下的歷史包袱,因為知道問題在那邊,但卻又推不動革新,那還能怎麼辦呢?當然是鬧脾氣走人啊!

所以在 2005 年,Ceki Gülcü 離開了 Apache,並自立門戶,實作了另外一個 Interface,Slf4j。Slf4j 可以說是針對 JCL 所開發的另一個 Interface,為了想要讓原本使用 JCL 的使用者可以簡單的轉移至 Slf4j,Ceki Gülcü 替 JCL 與 Slf4j 搭建了一座橋樑(Adapter),也就是 jcl-over-slf4j.jar。並且想要可以好好的支援 Log4j ,也加上了 slf4j-log4j12.jar

這代表如果你的應用原本是使用 JCL 介面,並且用 Log4j 輸出 Log 的話,Slf4j 會重新引導 JCL 的輸出至 Slf4j ,並統一用 Slf4j 的介面透過 Log4j 來輸出 Log。(Slf4j 就是針對 JCL,怎樣!)

然而,如果你的應用是在一開始就直接導入 Slf4j + Log4j,但後續又一定要使用 JCL 作為管理 Log 的介面,那要怎麼辦?拔掉 Slf4j 嗎?

沒有,Ceki Gülcü 表示:「Slf4j 要成為王,誰都不可以離開 Slf4j,讓我來幫你們搭建其他橋梁吧!」。也因此,slf4j-jcl.jar 就誕生了

既然都搭這麼多橋了,我 Slf4j 就要通吃,所有的橋我都建立!

因此 Ceki Gülcü 又特別對 Log4j 加入了一個 log4j-over-slf4j.jar,使得原本使用 Log4j 的使用者可以將介面統一至使用 Slf4j。另外對於只加入戰場一下下的 JUL 也沒有放過,在 2008 年也陸續地加入了跟 JUL 相關的 Adapter。

到這裡為止,你就可以統一使用 Slf4j 的介面,統一管理當前有的 Logging Framework。在 Slf4j 的官網說明裡面,你也可以找到如下說明:

這下看的出來 Ceki Gülcü 才是地圖炮了吧!可是這麼做的用意到底是甚麼?

Logback (2006)

其實 Ceki Gülcü 自己也知道在一開始做出來的 Log4j 是有點效能上或使用上的限制,為了想要讓自己創造出來的東西更完美,但卻又已經離開 Apache 了,所以決定翻掉重來,這就是第三套 Logging Framework ─ Logback。

在 2006 年的二月,Ceki Gülcü 建立了 Logback 的網站,並且在半年後發布了 Logback 的第一版。Logback 完美的實現了自己的手作 ─ Slf4j,先前提供了各種 Adapter 來攏絡所有 Log4j 以及 JUL 的用戶使用 Slf4j,後續要讓使用者放棄使用 Log4j 以及 JUL,使用 Logback,來稱霸整個 Logging 的市場。

其實 Ceki Gülcü 把 Logback 拆成幾個部分,個別是「logback-core.jar」、「logback-classic.jar」以及「logback-access.jar」。

  • logback-core,主要作為 logback-classic logback-access 的建構基礎
  • logback-classic,讓你可以輕鬆的在 Logback、Log4j 以及 JUL 中輕鬆切換
  • logback-access,與 Servlet 的容器做整合,例如 Tomcat 或 Jetty,提供在造訪 HTTP 時的 Log 紀錄功能,也可以輕鬆的建立你自己的 Log 模組於logback-core

Logback 在效能、使用記憶體用量、官方文件、寫出速度等部分,都比 Log4j 的表現還要好,並且自成一氣的用 Slf4j 來實現這個 Logging Framework,可以捨棄那些多餘的 Adapter,這確實吸引了不少使用者,也著實的大大的打臉了 Apache 正在維護的 Log4j。

Apache Log4j2 (2012)

Slf4j + Logback 的猖獗,總算是讓 Apache 忍不住了,Java 界的龍頭怎麼可能可以受的了「有人」搶走了他的市場,因此 Apache 就發布了 Log4j2。

古人喻:「己所不欲,勿施於人」。沒有這回事!Apache 說:「以牙還牙,以眼還眼」。Apache 所提出的 Log4j2,就好比 Ceki Gülcü 的 Slf4j,透過各種 Adapter,打下全世界。

奇妙的是,Log4j2 並無法與 Log4j1.x 互相直接進行切換,主要的原因還是因為架構差太多了。Log4j2 針對效能等等提升了許多,也將 Log4j2 拆成了幾個部分 ,「log4j-core.jar」以及「log4j-api.jar」。(有沒有覺得很熟悉,好像在 Logback 的部分出現過一次...)

  • log4j-core.jar,是 Logging Framework
  • log4j-api,是 Logging Interface

誰也不讓誰的結果,就會像下面的關係圖一樣崩潰...

神仙打架就是這麼可怕,JUL 只能默默接受猛烈砲火的轟炸。而未來會不會又出現更多的 Logging Framework,讓這個世界更崩壞呢。(拜託停止吧,這要逼死誰 XDD)

文末

這樣走過一輪整個 Java 在 Logging 發展的歷史過程,更明白了不同 Logging Interface 對於不同的 Logging Framework 之間的關係,像是到底要用哪一些 Adapter 才可以達到系統要使用的 Logging 配置,這...真的很亂。

其實在網路上也有一些類似本篇的文章,像是:

以及

但因為他們的圖實在太亂了,所以我又重新整理了一次。希望可以透過這篇文章,讓你更清楚他們之間的關係。

下一篇文章就會開始將先前我們搭建的 Spring Boot 專案加上 Logging,那我們就接著看下去吧!

--

--

Albert Hg
learning-from-jhipster

I am a programmer but love other things. I am a nobody but keep myself going. I am a person who wishes to reach the heaven but lost the wings.