文章目錄
根據 SpringBoot
v2.2.1.RELEASE
的官方文檔
日誌
日誌框架包括兩種:
- 日誌門面——日誌的一個抽象層
- 日誌的實現
日誌的抽象層 | 日誌的實現 |
---|---|
JCL(Jakarta Commons Logging) SLF4j(Simple Logging Facade for Java) jboss-logging | Log4j 、JUL(java.util.logging) Log4j2 Logback |
在使用時應該從左邊選取一個抽象層,右邊選取一個實現框架。
SpringBoot使用 Commons Logging
作爲內部日誌記錄,但保留了底層的日誌實現。提供了對於java util logging
、Log4j2
、Logback
的默認配置。logger都預先配置爲使用控制檯輸出,但可以選擇使用文件輸出。
默認情況下,使用Logback
進行日誌記錄。
1、日誌格式
SpringBoot的默認日誌輸出類似於:
2020-03-04 13:52:20.301 INFO 7169 --- [ main] s.Springboot01HelloworldApplicationTests : No active profile set, falling back to default profiles: default
2020-03-04 13:52:21.097 INFO 7169 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-03-04 13:52:21.312 INFO 7169 --- [ main] s.Springboot01HelloworldApplicationTests : Started Springboot01HelloworldApplicationTests in 1.317 seconds (JVM running for 2.174)
輸出以下項:
- 日期和時間:精度爲毫秒,易於排序
- 日誌級別:
ERROR
,WARN
,INFO
,DEBUG
, orTRACE
- 進程ID
---
標誌日誌信息的開始- 線程名稱:用方括號擴起來(在控制檯輸出時可以會被截斷)
- 記錄器名稱:通常是類名(通常縮寫)
- 日誌消息
Logback沒有
FATAL
級別,歸於了ERROR
。
2、控制檯輸出
默認情況下,日誌會輸出到控制檯上。默認ERROR
、WRAN
和INFO
級別的日誌會被記錄。能夠通過--dubug
來啓動應用程序開啓“debug”模式。
$ java -jar myapp.jar --debug
也能夠在
application.properties
中指定debug=true
開啓“debug”模式後,一些核心的logger(內置的容器, Hibernate, 並且 Spring Boot)會被配置來輸出更多的信息。啓用 debug
模式不會將應用程序配置爲以debug級別記錄所有消息。
當然也可以通過同樣的方式開啓 trace
模式。
2.1 彩色輸出
如果你的 terminal
支持 ANSI
,彩色輸出能夠提高可讀性。可以通過設置 spring.output.ansi.enabled
爲支持的值
來改變默認的自動檢測(detect)。
通過使用 %clr
轉化字符來配置彩色編碼。如下示例:
%clr(%5p)
Level | Color |
---|---|
FATAL |
Red |
ERROR |
Red |
WARN |
Yellow |
INFO |
Green |
DEBUG |
Green |
TRACE |
Green |
另外,你可以通過將顏色或樣式作爲轉換選項來指定應該使用的顏色或樣式。在下面的例子中,會使文本變成黃色:
%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){yellow}
支持的顏色和樣式:
blue
cyan
faint
green
magenta
red
yellow
3、文件輸出
SpringBoot的日誌默認只會輸出在控制檯中,如果想要記錄日誌到文件中,需要設置logging.file.name
和 logging.file.path
屬性(可以在application.properties
文件)。
下面的表格顯示了 logging.*
如果配合使用:
logging.file.name |
logging.file.path |
Example | Description |
---|---|---|---|
(無) | (無) | 僅僅在控制檯輸出 | |
Specific file | (無) | my.log |
寫入指定的目錄文件。名稱可以是絕對位置或相對位置 |
(無) | Specific directory | /var/log |
把spring.log 文件寫入 指定的目錄。名稱可以是絕對位置或相對位置 |
當日志文件達到10 MB時,就會循環保存(意味着1個文件的大小隻能是10MB,達到後就會換一個文件存放),並且與控制檯輸出一樣,默認情況下會記錄 ERROR/WRAN/INFO
日誌 。
可以通過 logging.file.max-size
屬性改變文件大小限制。
除非 logging.file.max-history
已經被設置,否則默認情況下保存最近7天的循環日誌文件。
日誌檔案的總大小能夠通過 logging.file.total-size-cap
設置上限,當總大小超過該閥值,就會刪除備份。
要在應用程序啓動時強制清除日誌存檔,需要使用 logging.file.clean-history-on-start
屬性。
每一個日誌的實現框架都有自己的配置文件。不論使用哪個日誌接口框架,配置文件還是做成日誌實現框架自己本身的配置文件;
4、日誌級別
日誌的輸出級別可以在Spring Environment
配置(例如:application.properties
,環境變量)。
配置方法:
-
logging.level.<logger-name>=<level>
,其中的level
可選爲:TRACE
、DEBUG
、INFO
、WRAN
、ERROR
、FATAL
、OFF
。#root的logger能夠通過 `loggin.level.root` 配置 logging.level.root=warn logging.level.org.springframework.web=debug logging.level.org.hibernate=error logging.level.com.springboot=trace
-
環境變量配置:
LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUG
將設置org.springframework.web
的輸出爲DEBUG
級別。
5、日誌分組
能夠把相關的logger放到一個組統一管理。
例如,定一個“tomcat”組:
logging.group.tomcat=org.apache.catalina, org.apache.coyote, org.apache.tomcat
統一管理“tomcat”組中的所有logger:
logging.level.tomcat=TRACE
SpringBoot包含了一些預定義的日誌記錄組,它們可以直接使用:
Name | Loggers |
---|---|
web | org.springframework.core.codec , org.springframework.http , org.springframework.web , org.springframework.boot.actuate.endpoint.web , org.springframework.boot.web.servlet.ServletContextInitializerBeans |
sql | org.springframework.jdbc.core , org.hibernate.SQL , org.jooq.tools.LoggerListener |
6、自定義log配置
springBoot的自動配置會檢測類路徑的類庫來自動激活相應的日誌系統,可以提供一個合適的配置來進一步的自定義配置。這個配置應該在 classpath
的根目錄或者被屬性logging.config
指定的目錄。
你可以使用 org.springframework.boot.logging.LoggingSystem
系統屬性來強制Spring boot使用一個特指的日誌系統。這個值應該是日誌系統具體實現的全限定類名。你也可以將這個值設置爲none,表示完全關閉日誌配置。
因爲loggin是在
ApplicationContext
創建之前初始化的,所以不能在@Configuration
配置的文件中控制日誌。自定義日誌系統或者關閉它的唯一方式是通過系統屬性(system properties)。
依賴於你的日誌系統,以下的文件會被加載:
Logging System | Customization |
---|---|
Logback | logback-spring.xml , logback-spring.groovy , logback.xml , or logback.groovy |
Log4j2 | log4j2-spring.xml or log4j2.xml |
JDK (Java Util Logging) | logging.properties |
官方推薦我們使用
-spring
變體作爲日誌的配置名(例如:使用logback-spring.xml
而不是logback.xml
)->原因:可以使用logback
的擴展功能,詳見7。如果你使用標準的配置位置,Spring將不能完全控制日誌的初始化。
爲了方便自定義log配置,以下是Spring Environment
轉爲系統屬性(System properties)
的一些屬性:
Spring Environment |
系統屬性 | 註釋 |
---|---|---|
logging.exception-conversion-word |
LOG_EXCEPTION_CONVERSION_WORD |
記錄異常時使用的轉換字。 |
logging.file.clean-history-on-start |
LOG_FILE_CLEAN_HISTORY_ON_START |
是否在啓動時清除存檔日誌文件(如果啓用了LOG_FILE)。(僅默認登錄設置支持。) |
logging.file.name |
LOG_FILE |
如果定義,它將在默認日誌配置中使用。 |
logging.file.max-size |
LOG_FILE_MAX_SIZE |
日誌文件的最大大小(如果啓用了LOG_FILE)。(僅默認登錄設置支持。) |
logging.file.max-history |
LOG_FILE_MAX_HISTORY |
要保留的最大歸檔日誌文件數(如果啓用了LOG_FILE)。(僅默認登錄設置支持。) |
logging.file.path |
LOG_PATH |
如果定義,它將在默認日誌配置中使用。 |
logging.file.total-size-cap |
LOG_FILE_TOTAL_SIZE_CAP |
要保留的日誌備份的總大小(如果啓用了LOG_FILE)。(僅默認登錄設置支持。) |
logging.pattern.console |
CONSOLE_LOG_PATTERN |
控制檯上要使用的日誌模式(stdout)。(僅默認登錄設置支持。) |
logging.pattern.dateformat |
LOG_DATEFORMAT_PATTERN |
記錄日期格式的附加模式。(僅默認登錄設置支持。) |
logging.pattern.file |
FILE_LOG_PATTERN |
文件中使用的日誌模式(如果LOG_FILE 已啓用)。(僅默認登錄設置支持。) |
logging.pattern.level |
LOG_LEVEL_PATTERN |
呈現日誌級別時使用的格式(默認%5p )。(僅默認登錄設置支持。) |
logging.pattern.rolling-file-name |
ROLLING_FILE_NAME_PATTERN |
過渡日誌文件名的模式(默認${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz )。(僅默認登錄設置支持。) |
PID |
PID |
當前進程ID(如果可能,並且尚未將其定義爲OS環境變量,則發現)。 |
當解析配置文件時,所有支持的日誌系統都能夠查詢系統屬性。可以看看spring-boot.jar中的配置樣例:
如果你想要在一個日誌屬性中使用佔位符,應該使用
Spring Boot
的語法而不是日誌框架的語法。特別地,如果使用Logback
,你應該使用:
作爲屬性名和默認值的分隔符,而不是使用-
。
7、Logback擴展
SpringBoot包含了許多對 Logback
日誌框架的擴展,可以幫助我們進行高級的配置。需要注意的是這些擴展功能只能在 logback-spring.xml
配置文件中使用。
因爲
logback.xml
配置文件加載時間過早,所以不能在其中使用擴展功能。只能在logback-spring.xml
中使用或者定義logging.config
屬性。
這些擴展不能和
Logback
的configuration scanning
一起使用。
7.1 Profile配置
使用 <springProfile>
標籤,你可以根據需要不同的環境需要包括或排除某些配置。
使用 name
屬性指定使用哪個配置文件。name
屬性可以是一個簡單的profile名稱,也可以是複雜的表達式。如下例:
<springProfile name="staging">
<!-- configuration to be enabled when the "staging" profile is active -->
</springProfile>
<springProfile name="dev | staging">
<!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
</springProfile>
<springProfile name="!production">
<!-- configuration to be enabled when the "production" profile is not active -->
</springProfile>
7.2 Environment屬性
<springProperty>
標籤讓你可以將Spring environment 中的屬性暴露給 Logback
使用。如果你想要在Logback
的配置中訪問 application.properties
文件中的值,這是十分方便的。
該標籤的工作方式與 Logback
的標準標籤 <property>
類似。不同的是,你不需要指定一個直接的 value
,只需要指定 source
屬性(這個屬性來自於Environment)。
如果你需要將屬性存儲在 local
範圍以外的地方,可以使用 scope
屬性。
如果需要一個默認值(以防該屬性沒有在 environment 中設置),可以使用 defaultValue
屬性。
下面的例子顯示瞭如何在 Logback 中使用這些屬性:
<springProperty scope="context" name="fluentHost" source="myapp.fluentd.host"
defaultValue="localhost"/>
<appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender">
<remoteHost>${fluentHost}</remoteHost>
...
</appender>
source
必須以短橫線命名的方式指定(例如:my.property-name
)。雖然屬性可能是以鬆散規則添加到Environment
8、SLF4j的使用
8.1 如何在系統中使用SLF4j
在開發的時候,日誌記錄方法的調用,不應該來直接調用日誌的實現類,而是調用日誌抽象層裏面的方法;
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");
}
}
如上圖所示,如果要使用 logback
作爲日誌實現類,需要導入slf4-api.jar
和logback-classic.jar
、logback-core.jar
。如果需要使用 log4j
作爲日誌實現類,需要導入slf4-api.jar
、log4j.jar
和一個適配器slf4j-log412.jar
。其餘類似。
每一個日誌的實現框架都有自己的配置文件。使用slf4j以後,配置文件還是做成日誌實現框架自己本身的配置文件;
8.2 其餘問題
框架都有着默認的日誌使用框架,比如Hibernate默認使用jboss-logging
作爲日誌抽象層,那如果現在在項目中統一都要使用 SLF4j
和 logback
,該如何呢?
如上圖所示,如果使用Commons logging Api
的框架要改成使用SLF4j
作爲日誌抽象層,則需要:
- 移除
commons-logging
的jar包 - 導入中間包
jcl-cover-slf4j.jar
(該包和commons-logging
包的類名、方法全部一樣,只是實現不同) - 導入
slf4-api.jar
和logback-classic.jar
、logback-core.jar
9、Logback.xml
<?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="/Users/yanjundong/Desktop/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>