日誌(Logging)

No System.out.print()

進行日誌追蹤的必要性
  1. 應對日益複雜化的系統
    1. 利於應付分散計算的巨大系統, 能有一致且集中的運作記載
    2. 進行日誌分析, 來對其系統進行最佳化
    3. 開發系統時, 設置監控點, 便於尋找系統問題
  2. 改進使用者體驗
    1. 記載使用者 Session 期間的所有動作
    2. 找尋使用者遭遇到的問題
    3. 分析使用者特徵的資料挖掘
  3. 進行系統或使用者的安全審計



Logging Level


日誌級別一共分為五個級別,從低到高以此是:
  1. Debug
  2. Info
  3. Warn
  4. Error
  5. Fatal
log4j 提供 TRACE, DEBUG, INFO, WARN, ERROR 及 FATAL 六種紀錄等級,但是 SLF4J 認為 ERROR 與 FATAL 並沒有實質上的差別,所以拿掉了 FATAL 等級,只剩下其他五種。



MDC / NDC


NDC(Nested Diagnostic Context)是 Neil Harrison 在名為《Patterns for Logging Diagnostic Messages》的書中提出的嵌套診斷環境的機制。這種機制的提出,主要為了減少多線程的系統為每個客戶單獨記錄日誌的系統開銷。在過去,區分兩個客戶的日誌輸出的常用方法是單獨為每個客戶機實例化新類別,但該方法會增加類別數量,並增加日誌記錄的管理開銷。Neil Harrison 提出的方法就是把用戶的上下文資訊放到嵌套式診斷環境 (NDC) 中。

NDC 為每一個線程管理一個堆棧。開發人員可以在代碼中合適的位置嵌入簡單的 push 和 pop 方法,用來維護堆棧。通常 push 進堆棧的是可以唯一標示客戶的上下文資訊,如 SessionID 或者客戶名稱,IP 地址等。因為每個客戶請求都會有單獨的 NDC 堆棧,因此日誌系統在輸出的時候會根據每個線程找到對應的堆棧,並在輸出日誌的時候附加上堆棧內的資訊。開發人員就可以很容易的在日誌中區分出各個不同客 戶所產生的日誌條目。

MDC(Mapped Diagnostic Context) 和 NDC 相似,也可以減少多線程的系統為每個客戶單獨記錄日誌的系統開銷。它同樣是為每個線程建立一個獨立的存儲空間,開發人員可以根據需要把資訊存入其中。不同 的是 MDC 使用 Map 的機制來存儲資訊,資訊以 key/value 對的形式存儲在 Map 中。

SLF4J 只支援 MDC,不支援 NDC。




Simple Logging Facade for Java (SLF4J)


SLF4J 為不同 Logging API 實作的專案, 提供一個簡單且一致的介面(Interface), 便於可以視需求和特定要求抽換更適當靈活的不同切換 Logging API 實作, 最低的 API 依賴性,
The Simple Logging Facade for Java or (SLF4J) serves as a simple facade or abstraction for various logging frameworks, e.g. java.util.logging, log4j and logback, allowing the end user to plug in the desired logging framework at deployment time.

Simple Logging Facade for Java (SLF4J) 是一套包裝 Logging 框架 的介面程式,以 Facade 模式實作。可以在軟體部署的時候決定要使用的 Logging 框架,目前主要支援的有 Java Logging APIlog4jlogback 等框架。以 MIT 授權方式發佈。

SLF4J 的作者就是 log4j 的作者 Ceki Gülcü,他宣稱 SLF4J 比 log4j 更有效率,而且比 Apache Commons Logging (JCL) 簡單、穩定。


Logging Framework

slf4j-log4j12-1.6.0-alpha2.jar
Binding for log4j version 1.2, a widely used logging framework. You also need to place log4j.jar on your class path.

slf4j-jdk14-1.6.0-alpha2.jar
Binding for java.util.logging, also referred to as JDK 1.4 logging

slf4j-nop-1.6.0-alpha2.jar
Binding for NOP, silently discarding all logging.

slf4j-simple-1.6.0-alpha2.jar
Binding for Simple implementation, which outputs all events to System.err. Only messages of level INFO and higher are printed. This binding may be useful in the context of small applications.

slf4j-jcl-1.6.0-alpha2.jar
Binding for Jakarta Commons Logging. This binding will delegate all SLF4J logging to JCL.




不同在這裡
logger.error("Temperature set to {}. Old temperature was {}.", t, oldT);
這是其他Logger不支持的功能。以前我們都要這樣寫
logger.error("Temperature set to "+t +". Old temperature was "+oldT+"." );
也就是經常說為什麼要加上log.isDebugalbe()判斷的原因之一,這樣做會減少字段串的合併,理解上減少JVM垃圾
提供字串內容替換的功能,會比較有效率
// 傳統的字串產生方式,如果沒有要紀錄 Debug 等級的訊息,就會浪費時間在產生不必要的訊息上
logger.debug("There are now " + count + " user accounts: " + userAccountList);

// 為了避免上述問題,我們可以先檢查是不是有開啟 Debug 訊息記綠功能,只是程式碼會比較複雜
if (logger.isDebugEnabled()) {
logger.debug("There are now " + count + " user accounts: " + userAccountList);
}

// 如果 Debug 等級沒有開啟,則不會產生不必要的字串,同時也能維持程式碼的簡潔
logger.debug("There are now {} user accounts: {}", count, userAccountList);





JavaSE - java.util.logging (JUL)


愚蠢的java.util.logging [愚蠢的java.util.*系列之二]

軟體套件 java.util.logging 的描述

提供 JavaTM 2 平臺核心日誌工具的類別和介面。Logging API 的中心目標是支持在客戶站點進行軟體的維護和服務。

使用日誌有 4 個主要目標:

  1. 由最終使用者和系統管理員進行問題診斷。這由簡單的常見問題日誌組成,可在本地解決或追蹤這些問題,如資源不足、安全失敗和簡單 的配置錯誤。
  2. 由現場服務工程師進行問題診斷。現場服務工程師使用的日誌資訊可以相當複雜和冗長,遠超過系統管理員的要求。通常,這 樣的資訊需要特定子系統中的額外日誌記錄。
  3. 由開發組織進行問題診斷。在現場出現問題時,必須將捕獲的日誌資訊返回到原開發團隊以供診斷。此日誌資訊可能非常詳 細,並且相當費解。這樣的資訊可能包括對特定子系統進行內部執行的詳細追蹤。
  4. 由開發人員進行問題診斷。Logging API 還可以用來說明除錯正在開發的應用程序。這可能包括由目標應用程序產生的日誌資訊,以及由低層級別的資源庫產生的日誌資訊。但是要注意,雖然這樣使用非常 合理,但是 Logging API 並不用於代替開發環境中已經存在的除錯和解析工具。




LOGBack


http://logback.qos.ch/
LOGBack:Java日誌的新進展 作者 Geoffrey Wiseman 譯者 郭曉剛 發佈於 2007年8月25日
SLF4J 的幾種實際應用模式--之二:SLF4J+Logback



Apache - log4j


http://logging.apache.org/log4j/index.html
  1. slf4j-api.jar & slf4j-log4j.jar
  2. add lib - log4j.jar & log4j.properties
我們需要修改下main方法,加載一下 log4j.properties 如;

Java Code

public static void main(String[] args) {
System.setProperty("log4j.configuration", "log4j.properties");
Slf4jTest slf = new Slf4jTest();
slf.testLog();
}





References




Comments