目錄
1.日志門面的介紹
常見的日志門面 :
常見的日志實現:
日志門面和日志實現的關系:
2.SLF4J 的介紹
業務場景(問題):
SLF4J的作用
SLF4J 的基本介紹
?日志框架的綁定(重點)
橋接舊的日志框架
SLF4J原理解析
3.SLF4J 的使用
非Springboot項目
?Springboot項目(重點)
Springboot中使用logback
Springboot中使用log4j2
1.日志門面的介紹
當我們的系統變的更加復雜的時候,我們的日志就容易發生混亂。隨著系統開發的進行,可能會更新不同的日志框架,造成當前系統中存在不同的日志依賴,讓我們難以統一的管理和控制。就算我們強制要 求所有的模塊使用相同的日志框架,系統中也難以避免使用其他類似spring,mybatis等其他的第三方框 架,它們依賴于我們規定不同的日志框架,而且他們自身的日志系統就有著不一致性,依然會出來日志 體系的混亂。
所以我們需要借鑒JDBC的思想,為日志系統也提供一套門面,那么我們就可以面向這些接口規范來開 發,避免了直接依賴具體的日志框架。這樣我們的系統在日志中,就存在了日志的門面和日志的實現。
常見的日志門面 :
JCL、slf4j
常見的日志實現:
JUL、log4j、logback、log4j2
日志門面和日志實現的關系:
通過這關系圖,就大概知道了其實日志門面就類似于一套標準的接口,然后不同的日志實現框架基于這套標準的接口去實現具體的功能。?
簡單來說,它僅僅是一個為Java程序提供日志輸出的統一接口,并不是一個具體的日志實現方案,就比如JDBC一樣,只是一種規則而已。所以單獨的slf4j是不能工作的,必須搭配其他具體的日志實現方案
日志框架出現的歷史順序:
log4j -->JUL-->JCL--> slf4j --> logback --> log4j2
2.SLF4J 的介紹
業務場景(問題):
現在開發項目都是使用maven進行構建開發,假設架構師a開發了一個通用組件A,他在程序中使用的是log4j組件進行日志輸出;程序員b自己之前一直在開發自己的業務模塊,并且他在程序中使用的是logback日志組件,突然有一天程序員b需要在自己的業務系統中使用架構師a的通用組件A,這個時候問題就出現了,由于兩套程序使用了不同的日志組件,程序員b除了要維護自己的logback日志組件配置,還需要維護通用組件A的日志配置,如何讓他們的日志輸出整合到一起,這個問題是很頭疼的。這時候,使用slf4j就可以完美解決問題
SLF4J的作用
* 1. 使用SLF4J框架,可以在部署時遷移到所需的日志記錄框架。
* 2. SLF4J提供了對所有流行的日志框架的綁定,例如log4j,JUL,Simple logging和NOP。因此可以 在部署時切換到任何這些流行的框架。
* 3. 無論使用哪種綁定,SLF4J都支持參數化日志記錄消息。由于SLF4J將應用程序和日志記錄框架分離, 因此可以輕松編寫獨立于日志記錄框架的應用程序。而無需擔心用于編寫應用程序的日志記錄框架。
* 4. SLF4J提供了一個簡單的Java工具,稱為遷移器。使用此工具,可以遷移現有項目,這些項目使用日志 框架(如Jakarta Commons Logging(JCL)或log4j或Java.util.logging(JUL))到SLF4J。
SLF4J 的基本介紹
簡單日志門面(Simple Logging Facade For Java) SLF4J主要是為了給Java日志訪問提供一套標準、規范 的API框架,其主要意義在于提供接口,具體的實現可以交由其他日志框架,例如log4j和logback等。 當然slf4j自己也提供了功能較為簡單的實現,但是一般很少用到。對于一般的Java項目而言,日志框架 會選擇slf4j-api作為門面,配上具體的實現框架(log4j、logback等),中間使用橋接器完成橋接。
官方網站: https://www.slf4j.org/
SLF4J是目前市面上最流行的日志門面。現在的項目中,基本上都是使用SLF4J作為我們的日志系統。
SLF4J日志門面主要提供兩大功能:
1. 日志框架的綁定
2. 日志框架的橋接
?日志框架的綁定(重點)
如前所述,SLF4J支持各種日志框架。SLF4J發行版附帶了幾個稱為“SLF4J綁定”的jar文件,每個綁定對應 一個受支持的框架。
?要切換日志框架,只需替換類路徑上的slf4j綁定。例如,要從java.util.logging切換到log4j,只需將 slf4j-jdk14-1.7.27.jar替換為slf4j-log4j12-1.7.27.jar即可。
SLF4J不依賴于任何特殊的類裝載。實際上,每個SLF4J綁定 在編譯時 都是硬連線的 , 以使用一個且只有一個特定的日志記錄框架。例如,slf4j-log4j12-1.7.27.jar綁定在編譯時綁定以使用log4j。在您的代碼 中,除了slf4j-api-1.7.27.jar 之外 ,您只需將您選擇的一個且只有一個綁定放到相應的類路徑位置。不要在類路徑上放置多個綁定。以下是一般概念的圖解說明。
?
注意點:在springboot項目中,如果項目中有多個實現類的話,項目是會直接報錯,無法運行,如下圖
橋接舊的日志框架
通常,您依賴的某些組件依賴于SLF4J以外的日志記錄API。您也可以假設這些組件在不久的將來不會切 換到SLF4J。為了解決這種情況,SLF4J附帶了幾個橋接模塊,這些模塊將對log4j,JCL和 java.util.logging API的調用重定向,就好像它們是對SLF4J API一樣。
橋接解決的是項目中日志的遺留問題,當系統中存在之前的日志API,可以通過橋接轉換到slf4j的實現
1. 先去除之前老的日志框架的依賴
2. 添加SLF4J提供的橋接組件
3. 為項目添加SLF4J的具體實現
遷移的方式:
如果我們要使用SLF4J的橋接器,替換原有的日志框架,那么我們需要做的第一件事情,就是刪除掉原 有項目中的日志框架的依賴。然后替換成SLF4J提供的橋接器。
注意問題:
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等對象,將無法產生效果。
橋接其實就是原來項目是使用的其他日志門面或者框架作為日志管理,現在像切換到使用slf4j來作為日志門面好做統一的日志管理,在不修改代碼的前提下,提出了橋接這種方式來兼容原來的老項目
SLF4J原理解析
1. SLF4J通過LoggerFactory加載日志具體的實現對象。
2. LoggerFactory在初始化的過程中,會通過performInitialization()方法綁定具體的日志實現。
3. 在綁定具體實現的時候,通過類加載器,加載org/slf4j/impl/StaticLoggerBinder.class
4. 所以,只要是一個日志實現框架,在org.slf4j.impl包中提供一個自己的StaticLoggerBinder類,在 其中提供具體日志實現的LoggerFactory就可以被SLF4J所加載
3.SLF4J 的使用
非Springboot項目
建項目
導入依賴
<!--slf4j core 使用slf4j必須添加--> ?
<dependency>
? ? <groupId>org.slf4j</groupId>
? ? <artifactId>slf4j-api</artifactId>
? ? <version>1.7.27</version>
?</dependency>
?<!--slf4j 自帶的簡單日志實現 -->
?<dependency>
? ? <groupId>org.slf4j</groupId>
? ? <artifactId>slf4j-simple</artifactId>
? ? <version>1.7.27</version>
?</dependency>
?編寫代碼
public void testQuick() throws Exception {//打印日志信息LOGGER.error("error");LOGGER.warn("warn");LOGGER.info("info");LOGGER.debug("debug");LOGGER.trace("trace");// 使用占位符輸出日志信息String name = "jack";Integer age = 18;LOGGER.info("用戶:{},{}", name, age);// 將系統異常信息寫入日志try {int i = 1 / 0;} catch (Exception e) {// e.printStackTrace();LOGGER.info("出現異常:", e);} }
?輸出結果
這種非springboot的項目大概流程是這樣子,具體更多的使用細節這里我就不做講解了,在開發中更多的是springboot項目,我重點介紹springboot項目
?Springboot項目(重點)
知識鋪墊:
SpringBoot支持多種日志框架,包括Logback、Log4j2和Java Util Logging(JUL)。默認情況下,如果你使用SpringBoot的starters啟動器,它將使用Logback作為日志框架。
- Logback:Logback是SpringBoot默認的日志框架,它是Log4j的繼任者,提供了更好的性能和可靠性。你可以通過在資源目錄下創建一個logback-spring.xml文件來配置Logback。
- Log4j2:Log4j2是Log4j的升級版,它在性能和功能上都有所提升,支持異步日志和插件機制。如果你想在SpringBoot中使用Log4j2,你需要添加相應的依賴并在配置文件中指定Log4j2作為日志框架。
- Java Util Logging(JUL):JUL是Java SE的默認日志框架,SpringBoot可以配置使用JUL作為日志框架,但一般不推薦使用,因為它的性能和靈活性相對較差。
簡單來說就是springboot項目已經幫我們內置好的日志框架,默認實現是SLF4J+logback。
所以如果我們項目中沒有做任何關于日志框架的處理,那么就會使用默認的組合
但在實際的開發中,往往需要對項目日志框架進行處理。開發中常用日志門面是SLF4J,常用到日志實現是logback和log42這二個具體的實現類。因為springboot項目默認使用的就是SLF4J,所以我們不需要在引入依賴的,只需要針對實現類做處理。
Springboot中使用logback
springboot項目默認的日志實現就是logback,所以我們不需要在引入依賴,如何配置logback相關的配置,有二種方式,一種在項目的配置文件種配置,一種是單獨建一個文件配置(方便管理)。我這里采用單獨第二種
logback會依次讀取以下類型配置文件:
logback.groovy
logback-test.xml
logback.xml 如果均不存在會采用默認配置
這里我建一個logback.xml的配置文件
<?xml version="1.0" encoding="UTF-8"?> <configuration><!--日志輸出格式:%-5level%d{yyyy-MM-dd HH:mm:ss.SSS}日期%c類的完整名稱%M為method%L為行號%thread線程名稱%m或者%msg為信息%n換行--><!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度%msg:日志消息,%n是換行符--><property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%-5level] %c %M %L [%thread] %m%n"/><!--Appender: 設置日志信息的去向,常用的有以下幾個ch.qos.logback.core.ConsoleAppender (控制臺)ch.qos.logback.core.rolling.RollingFileAppender (文件大小到達指定尺寸的時候產生一個新文件)ch.qos.logback.core.FileAppender (文件)--><appender name="console" class="ch.qos.logback.core.ConsoleAppender"><!--輸出流對象 默認 System.out 改為 System.err--><target>System.out</target><!--日志格式配置--><encoderclass="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><!-- 日志文件存放目錄 --><property name="log_dir" value="./logs"></property><!--日志文件輸出appender對象--><appender name="file" class="ch.qos.logback.core.FileAppender"><!--日志格式配置--><encoderclass="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder><!--日志輸出路徑--><file>${log_dir}/logback.log</file></appender><!-- 生成html格式appender對象 --><appender name="htmlFile" class="ch.qos.logback.core.FileAppender"><!--日志格式配置--><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="ch.qos.logback.classic.html.HTMLLayout"><pattern>%level%d{yyyy-MM-ddHH:mm:ss}%c%M%L%thread%m</pattern></layout></encoder><!--日志輸出路徑--><file>${log_dir}/logback.html</file></appender><!-- 日志文件拆分和歸檔的appender對象--><appender name="rollFile"class="ch.qos.logback.core.rolling.RollingFileAppender"><!--日志格式配置--><encoderclass="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder><!--日志輸出路徑--><file>${log_dir}/roll_logback.log</file><!--指定日志文件拆分和壓縮規則--><rollingPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!--通過指定壓縮文件名稱,來確定分割文件方式--><fileNamePattern>${log_dir}/rolling.%d{yyyy-MM-dd}-%i.log</fileNamePattern><!--文件拆分大小--><maxFileSize>50MB</maxFileSize></rollingPolicy></appender><!--用來設置某一個包或者具體的某一個類的日志打印級別、以及指定<appender>。<loger>僅有一個name屬性,一個可選的level和一個可選的addtivity屬性name:用來指定受此logger約束的某一個包或者具體的某一個類。level:用來設置打印級別,大小寫無關:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和OFF,如果未設置此屬性,那么當前logger將會繼承上級的級別。additivity:是否向上級loger傳遞打印信息。默認是true。<logger>可以包含零個或多個<appender-ref>元素,標識這個appender將會添加到這個logger--><!--也是<logger>元素,但是它是根logger。默認debuglevel:用來設置打印級別,大小寫無關:TRACE, DEBUG, INFO, WARN, ERROR, ALL和 OFF,<root>可以包含零個或多個<appender-ref>元素,標識這個appender將會添加到這個logger。--><root level="INFO"><appender-ref ref="console"/><appender-ref ref="rollFile"/></root> </configuration>
編寫測試類
public class LogbackTest {public static final Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class);@Testpublic void logbackTest(){LOGGER.error("error"); //錯誤信息,不會影響程序運行LOGGER.warn("warn"); //警告信息,表示系統運行可能出現的異常LOGGER.info("info"); //提示信息,記錄系統運行,io操作等LOGGER.debug("debug"); //調試信息,一般在開發中使用LOGGER.trace("trace"); //追蹤信息,記錄程序所有的流程信息// 占位符輸出日志String name = "jack";Integer age = 18;LOGGER.info("用戶姓名:{},年齡:{}",name,age);int i = 1;try {i = i/0;} catch (Exception e) {LOGGER.info("出現異常",e);}} }
運行效果:
未配置logback.xml前的輸出效果
配置后的輸出效果
總結:在springboot?使用logback非常的簡單,你只需要通過配置文件去配置它就好了
Springboot中使用log4j2
?因為springboot項目內置日志實現是logback,所以如果我們要使用log42的話,需要移除默認的依賴
<dependency>
? ? <groupId>org.springframework.boot</groupId>
? ? <artifactId>spring-boot-starter-web</artifactId>
? ? <!--排除默認spring-boot-starter-logging啟動器-->
? ? <exclusions>
? ? ? ? <exclusion>
? ? ? ? ? ? <groupId>org.springframework.boot</groupId>
? ? ? ? ? ? <artifactId>spring-boot-starter-logging</artifactId>
? ? ? ? </exclusion>
? ? </exclusions>
</dependency>
加入?log4j2的依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId> </dependency>
?
在src/main/resources目錄下創建一個名為log4j2-spring.xml的配置文件,Spring Boot會默認加載這個配置文件。Spring Boot官方推薦優先使用帶有-spring的文件名作為日志配置。
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"><!-- 定義全局變量,日志文件路徑和格式 --><Properties><Property name="log.path">./dev</Property><Property name="log.name">log4j2</Property><Property name="file.pattern">%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{50} - %msg%n</Property></Properties><!-- 控制臺輸出配置 --><Appenders><Console name="STDOUT" target="SYSTEM_OUT"><PatternLayout pattern="${file.pattern}"/><ThresholdFilter level="DEBUG"/></Console><!-- 文件輸出配置 --><RollingFile name="INFO_FILE" fileName="${log.path}/${log.name}.log4j2.log"filePattern="${log.path}/%d{yyyy-MM-dd}/${log.name}.info.%d{yyyy-MM-dd}-%i.log"><PatternLayout pattern="${file.pattern}"/><LevelMatchFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/><!-- 每個文件最大10MB --><SizeBasedTriggeringPolicy size="10MB"/><!-- 最多保留30天的歷史記錄 --><DefaultRolloverStrategy max="30"/></RollingFile><!-- 文件輸出配置 --><RollingFile name="ERROR_FILE" fileName="${log.path}/${log.name}.error.log"filePattern="${log.path}/%d{yyyy-MM-dd}/${log.name}.error.%d{yyyy-MM-dd}-%i.log"><PatternLayout pattern="${file.pattern}"/><LevelMatchFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/><!-- 每個文件最大10MB --><SizeBasedTriggeringPolicy size="10MB"/><!-- 最多保留30天的歷史記錄 --><DefaultRolloverStrategy max="30"/></RollingFile></Appenders><!-- 設置root logger --><Loggers><Root level="INFO"><AppenderRef ref="STDOUT"/><AppenderRef ref="INFO_FILE"/><AppenderRef ref="ERROR_FILE"/></Root></Loggers> </Configuration>
?運行效果
?如何是出現如上圖,就代表使用的是log4j2這個日志實現了
總的來說,推薦使用Logback,配置簡單,性能也還不錯,而且是SpringBoot的默認日志框架
這里對于logback和log4j2的使用只是基本的使用,對于更多的使用細節,后續我會分別出對應實現框架的文章,文章到這里就結束了,如有不足,歡迎指正