簡介
任何的軟件系統,日志都是非常重要的一部分。良好統一的日志規范會大大提高應用程序的可維護性、可靠性,並進而提高開發效率,指導業務。在早期,Java工程師往往都是利用 System.err.println
或 System.out.println
將 Java 應用內部的狀態信息或錯誤消息打印到系統的控制台中,這種簡易的保存方式顯然無法滿足保存日志信息所需的持久性和便利性等要求。所以,SUN 公司在發布 JDK 1.4 時,在 java.util.logging
包提供了一個日志框架。通常,直接使用 JUL
表示該框架。利用 JUL
的 API,Java 工程師可以輸出不同重要級別(比如 error、info 和 debug)的日志信息到一個集中的位置(比如 rotating file)。同時,Java 工程師可以完全控制輸出日志信息的重要級別和輸出格式。
框架概述
筆者認為,學習任何一門新技術或新概念的最佳方式都是 先整體后細節。所以,筆者先拋出 JUL
的框架概述圖:
- Application 將多種級別(level)的日志信息傳遞給 Logger 對象;
- Logger 對象使用 Level 和 Filter 對接受到的日志信息進行過濾;將日志信息轉換成 LogRecord 對象后傳遞給 Handler 對象;
- Handler 對象使用 Level 和 Filter 對接受到的 LogRecord 對象進行過濾;並使用 Formatter 格式化 LogRecord 對象並輸出到外部的文件或者數據庫中。
- Logger 對象之間存在着父子層級關系,這種層級關系是通過 Logger 對象的名稱來決定。
LogManager(日志管理器)
在 JUL
被 JVM 加載時,會有一個 LogManager 對象被創建出來作為全局組件而存在。這個全局組件主要負責創建和管理 Logger 對象,同時生成和維護全局的日志配置信息,這個全局配置信息可能是從配置文件中讀取而來,也可能是從配置類讀取而來。在默認配置的情況下,LogManager 只創建一個Level 為 Level.INFO 的 ConsoleHandler,該 ConsoleHandler 的日志信息輸出目的地是 System.err
。同時,這個 ConsoleHandle 屬於 LogManager 中的 root logger(根記錄器)。
在 Java 應用所使用的某個 JVM 中,有且僅有一個 LogManager 對象存在。通常,Java 工程師可以使用如下的代碼獲取該 LogManager 實例對象:
LogManager manager = LogManager.getLogManager();
通常情況下,Java 工程師都不要與該 LogManager 對象直接交互,除非某些特殊情形。比如重新加載配置類或配置文件,這種情況可以使用如下所示的實例代碼:
// 重讀配置類或配置文件 manager.readConfiguration(); // 重讀特定位置的配置類與配置文件 manager.readConfiguration(inputStream);
通過使用 LogManager 的 getLoggingMXBen() 方法,可以獲取一個 MXBen(Java Management Extensions)。簡單地實例代碼如下:
LoggingMXBean mxBean = manager.getLoggingMXBen();
當然,LogManager 還有很多其他的方法與特性,有興趣的同學可以進一步查看 JavaDoc 或者源碼。
Logger(日志記錄器)
JUL
的主要入口類是 java.util.Logger
。進行日志記錄的第一步就是創建一個 Logger 對象:
Logger logger = Logger.getLogger("www.tiantianbianma.com");
傳遞給 Logger 類中 getLogger 工廠方法的字符串 “www.tiantianbianma.com” 就是所創建的 Logger 對象的名稱。
在實際的項目開發中,一般的做法是使用當前 Java 類的名稱或所在包的名稱作為 Logger 對象的名稱。一個常見的示例代碼如下:
public class Application { Logger logger = Logger.getLogger(this.getClass().getName()); }
如果需要一個靜態的 Logger 對象,示例代碼如下:
public class Application { static Logger logger = Logger.getLogger(Application.class.getName()); }
如果需要查詢 Logger 對象的名稱,可以使用 getName() 方法。
String loggerName = logger.getName();
使用 Logger 對象進行日志記錄的方式很多,部分方式的示例代碼如下:
log (Level level, String message);
log (Level level, String message, Object param);
logp (Level level, String sourceClass, String sourceMethod, String msg);
logrb (Level level, String sourceClass, String sourceMethod, String bundle, String msg);
entering (String sourceClass, String sourceMethod);
...