1. 程式人生 > >SpringBoot日誌及原理

SpringBoot日誌及原理

一、SpringBoot日誌:選用SLF4j(介面)和logback(實現類),除了上述日誌框架,市場上還存在JUL(java.util.logging)、JCL(Apache Commons Logging)、Log4j、Log4j2、SLF4j、jboss-logging等。SpringBoot在框架內部使用JCL,SpringBoot的spring-boot-starter-logging採用了SLF4j+logback的形式,SpringBoot也能自動適配(jul、log4j2、logback)並簡化配置。其實logback是log4j的升級版,因為log4j在效能上有缺陷,且SLF4j也是logback的開發者開發的一個日誌介面(日誌門面)。

日誌門面 日誌實現

JCL(Jakarta Commons Logging)

SLF4J(Simple Logging Facade for Java)

Jobss-logging

Log4j

JUL(Java Util Logging)

Log4j2

Logback

二、SLF4j使用:1)、以後開發的時候,日誌記錄方法的呼叫,不應該來直接呼叫日誌的實現類,而是呼叫日誌抽象類層裡面的方法。
 ● 給系統裡面匯入slf4j的jar和logback的實現jar,Java類中的使用如下所示:很常用

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    public class HelloWorld {
      public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(HelloWorld.class);//記錄器
        logger.info("Hello World");
      }
    }

  ● 根據SLF4J抽象類,提供實現類的時候,SLF4j官方提供的配置邏輯如下所示,有的需要加入整合的jar包。


  ● 注意:每一個日誌的實現框架都有自己的配置檔案。使用slf4j以後,配置檔案還是做成日誌實現框架自己本身的配置檔案

 2)、常見問題:同一個系統中,包涵多種框架可能就會使用多種日誌記錄(slf4j+logback)、Spring(commons-logging)、Hibernate(Jboss-logging)、MyBatis等,如果我們要統一使用slf4j記錄日誌,思想如下:
    ✔  將系統中其他日誌框架先排除出去;
    ✔  用中間包替換原有的日誌框架;
    ✔  我們匯入slf4j唯一日誌的實現;具體可見下方,官方給出的圖解:


三、Spring Boot日誌關係:測試springBoot的日誌使用,首先引入日誌的starter啟動器。
 ☞ 首先我們檢視下pom.xml中的依賴關係:右鍵——>Diagrams——>Show Dependencies...  

 ☞ 可以檢視到我們我們使用最多的啟動器:spring‐boot‐starter

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring‐boot‐starter</artifactId>
</dependency>

 ☞ 而我們使用的日誌啟動器spring‐boot‐starter‐logging依賴於spring‐boot‐starter,SpringBoot使用它來做日誌功能:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring‐boot‐starter‐logging</artifactId>
</dependency>

 ☞ 而spring‐boot‐starter‐logging啟動器的底層依賴實現關係如下:

 ☞ 總結:1)、SpringBoot底層也是使用slf4j+logback的方式進行日誌記錄的。
       2)、SpringBoot也考慮到了其他日誌,將他們都替換成了slf4通過替換包。
       3)、中間替換包?我們通過引入的jar包檢視究竟:

      4)、如果我們引入了其他框架?一定要把這個框架的預設日誌依賴移除掉。我們點進spring‐boot‐starter‐logging會發現如下SpringBoot引入springframework依賴時自動排除了commons-logging依賴,避免衝突,我們也應如此。

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring‐core</artifactId>
        <exclusions>
            <exclusion>
                <groupId>commons‐logging</groupId>
                <artifactId>commons‐logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    總結:SpringBoot能夠自動適配所有的日誌,而且底層使用slf4j+logback的方式記錄日誌,引入其他框架的時候,只需要把這個框架依賴的日誌框架排除掉。

四、日誌使用:1)、預設配置:SpringBoot已經幫我們配置好了日誌,日誌級別=info。

	//日誌記錄器
	Logger logger = LoggerFactory.getLogger(getClass());

	@Test
	public void contextLoads() {
		//日誌的級別:優先順序trace<debug<info<warn<error
		//可以調整輸出的日誌級別;日誌就只會在這個級別及以後的高級別生效
		logger.trace("這是跟蹤日誌");
		logger.debug("這是除錯日誌");
		//SpringBoot預設使用的是 info級別的;root級別
		logger.info("這是自定義");
		logger.warn("這是警告日誌");
		logger.error("這是錯誤日誌");
	}

  2)、修改日誌級別,可以細化到給包分配級別,配置檔案中配置如下:

    #修改列印級別 == 可以細化到包級別
    logging.level.com=trace
    #下面path與file都不指定時,日誌輸出到控制檯,兩個都指定時,file生效
    #指定目錄,檔名預設spring.log中,如下是在當前磁碟根路徑下建立var檔案和裡面的log檔案。
    logging.path=/var/log  
    #指定檔名 當前專案下生成springboot.log日誌,也可以指定到本地檔案中d:/springboot.log等
    logging.file=springboot.log
    #在控制檯日誌輸入的格式
    logging.pattern.console=%d{yyyy‐MM‐dd} [%thread] %‐5level %logger{50} ‐ %msg%n
    #在檔案中日誌輸出的格式
    #日誌輸出格式:
    #    %d表示日期時間,
    #    %thread表示執行緒名,
    #    %‐5level:級別從左顯示5個字元寬度
    #    %logger{50} 表示logger名字最長50個字元,否則按照句點分割。
    #    %msg:日誌訊息,
    #    %n是換行符
    logging.pattern.file=%d{yyyy‐MM‐dd} [%thread] %‐5level %logger{50} ‐ %msg%n

  3)、SpringBoot的預設日誌配置位於spring-boot-1.5.17.RELEASE.jar:org.springframework.boot:logging檔案,例如檢視logback資料夾中的base.xml和defaults.xml。

<!-- base.xml部分內容 -->
<included>
	<include resource="org/springframework/boot/logging/logback/defaults.xml" />
	<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
	<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
	<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
        <!-- 預設級別 -->
	<root level="INFO">
		<appender-ref ref="CONSOLE" />
		<appender-ref ref="FILE" />
	</root>
</included>

   4)、如果覺得日誌配置不夠用,客戶可以自己指定配置:給類路徑下(resource)放每個日誌框架自己定義的配置檔案即可(如下名稱的日誌檔案),這樣SpringBoot就不適用預設配置。可以參考SpringBoot官網中的logging模組。

 ● 例如建立如上的logback.xml放入resource中,將會直接被日誌框架直接識別了。內容如下,作為參考:

<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:當此屬性設定為true時,配置檔案如果發生改變,將會被重新載入,預設值為true。
scanPeriod:設定監測配置檔案是否有修改的時間間隔,如果沒有給出時間單位,預設單位是毫秒當scan為true時,此屬性生效。預設的時間間隔為1分鐘。
debug:當此屬性設定為true時,將打印出logback內部日誌資訊,實時檢視logback執行狀態。預設值為false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
    <!-- 定義日誌的根目錄 -->
    <property name="LOG_HOME" value="/app/log" />
    <!-- 定義日誌檔名稱 -->
    <property name="appName" value="atguigu-springboot"></property>
    <!-- ch.qos.logback.core.ConsoleAppender 表示控制檯輸出 -->
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <!--
        日誌輸出格式:
			%d表示日期時間,
			%thread表示執行緒名,
			%-5level:級別從左顯示5個字元寬度
			%logger{50} 表示logger名字最長50個字元,否則按照句點分割。 
			%msg:日誌訊息,
			%n是換行符
        -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </layout>
    </appender>

    <!-- 滾動記錄檔案,先將日誌記錄到指定檔案,當符合某個條件時,將日誌記錄到其他檔案 -->  
    <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 指定日誌檔案的名稱 -->
        <file>${LOG_HOME}/${appName}.log</file>
        <!--
        當發生滾動時,決定 RollingFileAppender 的行為,涉及檔案移動和重新命名
        TimeBasedRollingPolicy: 最常用的滾動策略,它根據時間來制定滾動策略,既負責滾動也負責出發滾動。
        -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--
            滾動時產生的檔案的存放位置及檔名稱 %d{yyyy-MM-dd}:按天進行日誌滾動 
            %i:當檔案大小超過maxFileSize時,按照i進行檔案滾動
            -->
            <fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
            <!-- 
            可選節點,控制保留的歸檔檔案的最大數量,超出數量就刪除舊檔案。假設設定每天滾動,
            且maxHistory是365,則只儲存最近365天的檔案,刪除之前的舊檔案。注意,刪除舊檔案是,
            那些為了歸檔而建立的目錄也會被刪除。
            -->
            <MaxHistory>365</MaxHistory>
            <!-- 
            當日志文件超過maxFileSize指定的大小是,根據上面提到的%i進行日誌檔案滾動 注意此處配置SizeBasedTriggeringPolicy是無法實現按檔案大小進行滾動的,必須配置timeBasedFileNamingAndTriggeringPolicy
            -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <!-- 日誌輸出格式: -->     
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
        </layout>
    </appender>

    <!-- 
		logger主要用於存放日誌物件,也可以定義日誌型別、級別
		name:表示匹配的logger型別字首,也就是包的前半部分
		level:要記錄的日誌級別,包括 TRACE < DEBUG < INFO < WARN < ERROR
		additivity:作用在於children-logger是否使用 rootLogger配置的appender進行輸出,
		false:表示只用當前logger的appender-ref,true:
		表示當前logger的appender-ref和rootLogger的appender-ref都有效
    -->
    <!-- hibernate logger -->
    <logger name="com.atguigu" level="debug" />
    <!-- Spring framework logger -->
    <logger name="org.springframework" level="debug" additivity="false"></logger>

    <!-- 
    root與logger是父子關係,沒有特別定義則預設為root,任何一個類只會和一個logger對應,
    要麼是定義的logger,要麼是root,判斷的關鍵在於找到這個logger,然後判斷這個logger的appender和level。 
    -->
    <root level="info">
        <appender-ref ref="stdout" />
        <appender-ref ref="appLogAppender" />
    </root>
</configuration> 

 ● 當命名中帶有spring時,例如:logback-spring.xml:日誌框架就不直接載入日誌的配置項,由SpringBoot解析日誌配置,但可以使用SpringBoot的高階springProfile功能,如下配置。如果不帶spring使用springProfile標籤時就會出錯。

    <layout class="ch.qos.logback.classic.PatternLayout">
        <!-- 可以指定以哪種形式執行環境 -->
        <springProfile name="dev">
            <pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ‐‐‐‐> [%thread] ‐‐‐> %‐5level%logger{50} ‐ %msg%n</pattern>
        </springProfile>
        <springProfile name="!dev">
            <pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ==== [%thread] ==== %‐5level%logger{50} ‐ %msg%n</pattern>
        </springProfile>
    </layout>

五、切換日誌框架:根據官方文件如下配置:可以看出首先排除logging啟動器,依賴log4j2的啟動器即可。(排除:可以通過pom.xml的依賴檢視,右鍵Exclude。)

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter</artifactId>
	<exclusions>
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-logging</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

六、按天分類日誌:logback-spring.xml配置如下:

 <!--按天生成日誌--> 
 <appender name="logFile" class="ch.qos.logback.core.rolling.RollingFileAppender">                   
     <Prudent>true</Prudent> 
     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> 
         <FileNamePattern> applog/%d{yyyy-MM-dd}/%d{yyyy-MM-dd}.log </FileNamePattern> 
     </rollingPolicy> 
     <layout class="ch.qos.logback.classic.PatternLayout"> 
         <Pattern> %d{yyyy-MM-dd HH:mm:ss} -%msg%n </Pattern> 
     </layout> 
 </appender>