關於log4j、jul、jcl、slf4j等等日誌組件的理解
日誌組件:
我們經常在開發項目的時候,需要打印記錄項目過程中的一些日誌。那我們經常大概會用到 log4j、jul、jcl、slf4j、simple、nop、logback 等等,那我們就詳細介紹下這些組件是怎麼做日誌打印的
JUL:
JUL全稱Java util Logging是java原生的日誌框架,使用時不需要另外引用第三方類庫,相對其他日誌框架使用方便,學習簡單,能夠在小型應用中靈活使用。
架構介紹:
Loggers :被稱為記錄器,應用程序通過獲取Logger對象,調用其API來發佈日誌信息。Logger通常為應用程序訪問日誌系統的入口程序。
Appenders :也被稱為Handlers,每個Logger都會關聯一組Handlers,Logger會將日誌交給關聯Handlers處理,由Handlers負責將日誌做記錄。Handlers在此是一個抽象,其具體的實現決定了日誌記錄的位置可以是控制台、文件、網絡上的其他日誌服務或操作系統日 志等。
Layouts :也被稱為Formatters,它負責對日誌事件中的數據進行轉換和格式化。Layouts決定了數據在一條日誌記錄中的最終形式。
Level :每條日誌消息都有一個關聯的日誌級別。該級別粗略指導了日誌消息的重要性和緊迫,我可以將Level和Loggers,Appenders做關聯以便於我們過濾消息。
Filters :過濾器,根據需要定製哪些信息會被記錄,哪些信息會被放過。
總結:
用戶使用Logger來進行日誌記錄,Logger持有若干個Handler,日誌的輸出操作是由Handler完成的。
在Handler輸出日誌前,會經過Filter的過濾,判斷哪些日誌級別過濾放行哪些攔截,
Handler會將日誌內容輸出到指定位置(日誌文件、控制台等)。Handler在輸出日誌時會使用Layout,將輸出內容進行排版
案例:
public class JULTest { @Test public void test01() { // 1.獲取日誌記錄器對象 Logger logger = Logger.getLogger("jul"); // 2.日誌記錄輸出 logger.info("jul"); } }
日誌的級別:
jul中定義的日誌級別
java.util.logging.Level中定義了日誌的級別:
SEVERE(最高值)
WARNING 警告信息
INFO (默認級別)
CONFIG 配置信息
FINE debug級別信息,信息顆粒度最小
FINER debug級別信息
FINEST(最低值)debug級別信息,信息顆粒度最大
還有兩個特殊的級別:
OFF,可用來關閉日誌記錄。
ALL,啟用所有消息的日誌記錄。
日誌級別案例:
@Test public void testLogLevel() { // 1.獲取日誌對象 Logger logger = Logger.getLogger("jul"); // 2.日誌記錄輸出 logger.severe("severe"); logger.warning("warning"); logger.info("info"); logger.config("config"); logger.fine("fine"); logger.finer("finer"); logger.finest("finest"); }
由於默認級別是info, 所以以上日誌只會打印 info以上級別的日誌
修改日誌級別:
@Test public void testLogConfig() throws IOException { // 1.創建日誌記錄器對象 Logger logger = Logger.getLogger("jul"); // 一、自定義日誌級別 // a.關閉系統默認配置 logger.setUseParentHandlers(false); // b.創建handler對象 ConsoleHandler consoleHandler = new ConsoleHandler(); // c.創建formatter對象(簡單格式轉換對象) SimpleFormatter simpleFormatter = new SimpleFormatter(); // d.進行關聯 consoleHandler.setFormatter(simpleFormatter); logger.addHandler(consoleHandler); // e.設置日誌級別 logger.setLevel(Level.FINE); consoleHandler.setLevel(Level.FINE); // 二、輸出到日誌文件 FileHandler fileHandler = new FileHandler("d:/jul.log"); fileHandler.setFormatter(simpleFormatter); logger.addHandler(fileHandler); // 2.日誌記錄輸出 logger.severe("severe"); logger.warning("warning"); logger.info("info"); logger.config("config"); logger.fine("fine"); logger.finer("finer"); logger.finest("finest"); }
JCL:
JCL全稱為Jakarta Commons Logging,是Apache提供的一個通用日誌API。
它是為 “所有的Java日誌實現”提供一個統一的接口,它自身也提供一個日誌的實現,但是功能非常弱(SimpleLog)。所以一般不會單獨使用它。
他允許開發人員使用不同的具體日誌實現工具: Log4j, Jdk自帶的日誌(JUL)
JCL 有兩個基本的抽象類:Log(基本記錄器)和LogFactory(負責創建Log實例)。
默認使用 jul 的實現
案例:
1.添加依賴
<dependencies> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
2. 測試
public class JCLTest { @Test public void test() { // 創建日誌對象 Log log = LogFactory.getLog("jcl"); // 日誌記錄輸出 log.info("info"); } }
JCL原理:
1. 通過LogFactory動態加載Log實現類
2 . 日誌門面支持的日誌實現數組
3 . 獲取具體的日誌實現
LOG4J:
Log4j是Apache下的一款開源的日誌框架,通過在項目中使用 Log4J,我們可以控制日誌信息輸出到控制台、文件、甚至是數據庫中。我們可以控制每一條日誌的輸出格式,通過定義日誌的輸出級別,可以更靈活的控制日誌的輸出過程。方便項目的調試
log4j.properties(最簡單配置)
log4j.rootLogger=INFO,Console log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.layout=org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
案例:
1. 添加依賴
<dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
2. 測試
@Test public void test01() { // 獲取日誌記錄器對象 Logger logger = Logger.getLogger(Log4jTest.class); // 日誌記錄輸出 logger.info("hello log4j"); // 日誌測試 logger.info("info"); }
日誌的級別:
每個Logger都有一個日誌級別(log level),用來控制日誌信息的輸出。日誌級別從高到低分為:
fatal 指出每個嚴重的錯誤事件將會導致應用程序的退出。
error 指出雖然發生錯誤事件,但仍然不影響系統的繼續運行。
warn 表明會出現潛在的錯誤情形。
info 一般和在粗粒度級別上,強調應用程序的運行全程。
debug 一般用於細粒度級別上,對調試應用程序非常有幫助。(默認級別)
trace 是程序追蹤,可以用於輸出程序運行中的變量,顯示執行的流程。
還有兩個特殊的級別:
OFF,可用來關閉日誌記錄。
ALL,啟用所有消息的日誌記錄。
註:一般只使用 4個級別,優先級從高到低為 ERROR > WARN > INFO > DEBUG
slf4j:
簡單日誌門面(Simple Logging Facade For Java) SLF4J主要是為了給Java日誌訪問提供一套標準、規範的API框架,其主要意義在於提供接口,具體的實現可以交由其他日誌框架,例如log4j和logback等。當然slf4j自己也提供了功能較為簡單的實現,但是一般很少用到。對於一般的Java項目而言,日誌框架會選擇slf4j-api作為門面,通過綁定器綁定具體的實現框架(log4j、logback等)進行日誌打印,與第三方其它框架統一日誌的時候,中間使用橋接器完成橋接。
SLF4J是目前市面上最流行的日誌門面。現在的項目中,基本上都是使用SLF4J作為日誌系統。
SLF4J日誌門面主要提供兩大功能:
1. 日誌框架的綁定
2. 日誌框架的橋接
入門案例:
1. 添加依賴
<dependencies> <!--slf4j core 使用slf4j必須添加--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.26</version> </dependency> <!--slf4j 自帶的簡單日誌實現 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.27</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
2. 測試
public class Slf4jTest { // 聲明日誌對象 public final static Logger LOGGER = LoggerFactory.getLogger("slf4j"); @Test public void test01() { //打印日誌信息 LOGGER.info("info"); } }
綁定日誌的實現(Binding):
SLF4J支持各種日誌框架。SLF4J發行版附帶了幾個稱為「SLF4J綁定」的jar文件,每個綁定對應一個受支持的框架。
使用slf4j的日誌綁定流程:
1. 添加slf4j-api的依賴
2. 使用slf4j的API在項目中進行統一的日誌記錄
3. 綁定具體的日誌實現框架
1. 綁定已經實現了slf4j的日誌框架,直接添加對應依賴
2. 綁定沒有實現slf4j的日誌框架,先添加日誌的適配器,再添加實現類的依賴
4. slf4j有且僅有一個日誌實現框架的綁定(如果出現多個默認使用第一個依賴日誌實現)
通過maven引入常見的日誌實現框架:(根據實際情況選擇使用,除了引入下面其中一個,還不能少了 slf4j-api 的引用)
官方綁定器API地址: //www.slf4j.org/manual.html
1. logback
<!-- logback 日誌實現 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency>
2. nop
<!-- nop 日誌開關(不使用日誌功能) --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-nop</artifactId> <version>1.7.2</version> </dependency>
3. log4j
<!-- 綁定 log4j 日誌實現,需要導入適配器,還需要添加 log4j.properties 配置文件 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.26</version> </dependency> <!-- log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
4. jul
<!-- 綁定 jul 日誌實現,需要導入適配器 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.7.25</version> </dependency> <!-- 因為是java原生的日誌框架,已經內置了具體實現 -->
原理:
橋接其它框架日誌的實現(Bridging):
橋接解決的是項目中日誌的遺留問題,當系統中存在之前的日誌API,可以通過橋接轉換到slf4j的實現
1. 先去除之前老的日誌框架的依賴
2. 添加SLF4J提供的橋接組件
3. 為項目添加SLF4J的具體實現
4. 統一應用和框架的日誌實現
遷移的方式:
如果我們要使用SLF4J的橋接器,替換原有的日誌框架,那麼我們需要做的第一件事情,就是刪除掉原有項目中的日誌框架的依賴。然後替換成SLF4J提供的橋接器。
官方api地址: //www.slf4j.org/legacy.html
原理:
1. log4j
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.26</version> </dependency> <!-- 配置 log4j 的橋接器 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.25</version> </dependency>
2. logback
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.26</version> </dependency> <!-- 配置 log4j 的橋接器 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.25</version> </dependency> <!-- logback 日誌實現 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency>
3. jcl
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.26</version> </dependency> <!-- 配置 jcl 的橋接器 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.8</version> </dependency>
4. jul
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.26</version> </dependency> <!-- 配置 jul 的橋接器 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>1.7.25</version> </dependency>
註:
1. jcl-over-slf4j.jar(橋接)和 slf4j-jcl.jar(適配)不能同時部署。前一個jar文件將導致JCL將日誌系統的選擇委託給SLF4J,後一個jar文件將導致SLF4J將日誌系統的選擇委託給JCL,從而導致無限循環 。
2. log4j-over-slf4j.jar和slf4j-log4j12.jar不能同時出現,原因同上
3 . jul-to-slf4j.jar和slf4j-jdk14.jar不能同時出現,原因同上
4. 所有的橋接都只對Logger日誌記錄器對象有效,如果程序中調用了內部的配置類或者是Appender,Filter等對象,將無法產生效果。