一、前言
上篇介紹了 Spring Boot Maven 多模塊項目的搭建方法以及 MyBatis 的集成。通常在調試接口或者排查問題時我們主要借助於日志,一個設計合理的日志文件配置能大大降低我們的排查難度,本篇主要介紹 Logback 集成步驟。
二、集成 Logback
2.1 引入依賴包
其實 Spring Boot 提供的父工程中已經包含了所依賴的 Logback jar 包,可通過項目父 pom 中的 「spring-boot-starter-parent」>> 「spring-boot-dependencies」找到 Logback 的三個依賴包。
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
2.2 簡單日志配置
在自定義日志配置之前我們可以先嘗試一下 Spring Boot 默認的日志配置,可通過修改 application.properties 文件中的配置項設置。
① 更改默認日志級別
默認情況下 Spring Boot 從控制台打印出來的日志級別只有 ERROR、WARN、INFO 這三種,如果需要打印 DEBUG 級別的日志,可以使用以下配置項設置。
logging.level.root = DEBUG
② 將日志輸出到文件中
默認情況下 Spring Boot 只會在控制台打印日志,可以使用「 logging.path 」或「 logging.file 」其中一個配置項將日志輸出到文件中。
logging.path = ./logs
或
logging.file = ./logs/demo.log
注意事項:
- logging.path 和 logging.file 都可以是相對路徑或者絕對路徑
- 但它們兩個是不會疊加的,也就是說即使同時配置 logging.path = ./logs 與 logging.file = demo.log 也不會在 ./logs 目錄下 生成 demo.log 文件,實際結果是最終只在項目根目錄生成了 demo.log 文件。
- 當只配置 logging.path 時,會在該 path 下生成一個 spring.log 文件,該文件名是固定的無法修改,若 path 不存在則會自動創建該路徑。
2.3 自定義日志配置
我們可能需要將一些特定包或者特定級別的日志打印到單獨的文件中方便排查問題,顯然默認的日志配置並不能滿足我們需求,需要我們自定義。
2.3.1 Logback XML 基礎配置介紹
首先熟悉下常規的配置項,詳見:Logback XML 基礎配置詳解
2.3.2 自定義日志配置文件內容解析
然后在 demo-web 層的 resources 目錄下創建名為「 logback.xml 」的文件,具體內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 每隔一分鍾掃描配置文件 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 設置上下文名稱為 demo -->
<contextName>demo</contextName>
<!-- 定義日志輸出格式變量:%d表示時間 花括號內為時間格式 %level表示日志級別 %thread表示線程名 %logger{0}表示輸出日志的類名 [%line]表示行號用方括號包裹 %msg表示日志消息 %n換行 -->
<property name="log.pattern" value="[%d{'MM-dd HH:mm:ss,SSS'}] %level [%thread] %logger{0}[%line] - %msg%n"/>
<!-- 定義日志字符集 -->
<property name="log.charset" value="UTF-8"/>
<!-- 定義日志級別 -->
<property name="log.level" value="INFO"/>
<!-- 定義日志存放路徑 -->
<property name="log.path" value="logs"/>
<!-- 輸出到控制台 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!-- 日志輸出格式 -->
<encoder>
<!-- 日志字符集 -->
<charset>${log.charset}</charset>
<!-- 日志輸出格式 -->
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 時間滾動輸出日志 -->
<appender name="COMMON" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 寫入的文件名 -->
<file>${log.path}/common.log</file>
<!-- 追加到文件結尾 -->
<append>true</append>
<!-- 滾動策略:按照每天生成日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志歸檔路徑及文件名格式 -->
<fileNamePattern>${log.path}/common.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志文件保留天數 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<charset>${log.charset}</charset>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 單日志文件最大限制100兆 超過則將文件內容歸檔到按照 fileNamePattern 命名的文件中 源文件則清空 -->
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 級別過濾器匹配 ERROR 級別日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<charset>${log.charset}</charset>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<appender name="DB" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/db.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/db.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<charset>${log.charset}</charset>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 指定 com.example.demo.dao.mapper 包要使用的 appender 且不向上級傳遞 -->
<logger name="com.example.demo.dao.mapper" level="DEBUG" additivity="false">
<!-- 指定使用 DB 及 ERROR 這兩個 appender -->
<appender-ref ref="DB"/>
<appender-ref ref="ERROR"/>
</logger>
<!-- 根 logger -->
<root level="${log.level}">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="COMMON"/>
<appender-ref ref="ERROR"/>
</root>
</configuration>
2.3.3 多環境自定義日志配置
然而,上述配置中 <property> 標簽的值都是寫死的,但我們的項目環境可能有多套,每套環境的日志配置都有所區別,這就需要借助 Spring Boot 提供的 <springProfile> 及 <springProperty> 標簽解決。
① 首先將剛才新建的 「 logback.xml 」文件重命名為「 logback-spring.xml 」。
注:因為文件的命名與加載順序有關,logback.xml 早於 application.properties 加載,而 logback-spring.xml 晚於 application.properties 加載。而且 logback-spring.xml 中 Spring Boot 提供了一些特定的配置項支持,如 <springProperty>、<springProfile>。
② 其次將 <property> 標簽定義的配置項改為使用 <springProperty> 標簽聲明。
<springProperty scope="context" name="log.charset" source="log.charset" defaultValue="UTF-8"/>
<springProperty scope="context" name="log.level" source="log.level" defaultValue="INFO"/>
<springProperty scope="context" name="log.path" source="log.path" defaultValue="./logs"/>
<springProperty scope="context" name="log.pattern" source="log.pattern" defaultValue="[%d{'MM-dd HH:mm:ss,SSS',GMT+8:00}] %level [%thread] %logger{0}[%line] - %msg%n"/>
注:因為只有使用 <springProperty> 標簽才能使用 application.properties 文件中的配置項,它的工作方式與 Logback 標准的 <property> 類似,source 指定 application.properties 文件中的配置項。defaultValue 為默認值。
③ 使用 <springProfile> 標簽指定配置生效環境
<!-- 開發及測試環境才打印 SQL 日志 -->
<springProfile name="dev,test">
<!-- 指定 com.example.demo.dao.mapper 包要使用的 appender 且不向上級傳遞 -->
<logger name="com.example.demo.dao.mapper" level="DEBUG" additivity="false">
<!-- 指定使用 DB 及 ERROR 這兩個 appender -->
<appender-ref ref="DB"/>
<appender-ref ref="ERROR"/>
</logger>
</springProfile>
注:上述配置生效的前提是在 application.properties 文件中指定生效環境(即 spring.profiles.active = dev )
④ 啟動項目可以看到在項目根目錄生成 logs 目錄,目錄中有三個日志文件(即 common.log 、db.log 、error.log ),訪問 上篇的 http://localhost:8080/demo/test 接口后 db.log 輸出如下日志:
[01-30 17:58:05,296] DEBUG [http-nio-8080-exec-1] selectById[159] - ==> Preparing: SELECT `id`, `user_name` FROM `db_user` WHERE `id` = ?
[01-30 17:58:05,317] DEBUG [http-nio-8080-exec-1] selectById[159] - ==> Parameters: 1(Integer)
[01-30 17:58:05,373] DEBUG [http-nio-8080-exec-1] selectById[159] - <== Total: 1
三、結語
至此 Spring Boot 集成 Logback 的具體步驟介紹完畢,我們自定義了一個簡單的日志配置,也看到了最后的輸出結果。后續將繼續介紹其余中間件或者工具的集成步驟。