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...
![](https://img-blog.csdnimg.cn/20181101225436575.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poZW5nemhhb3lhbmcxMjI=,size_16,color_FFFFFF,t_70)
☞ 可以檢視到我們我們使用最多的啟動器: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>