文章目錄
- 一、前言
- 二、案例一:初識日志
- 三、案例二:使用Lombok輸出日志
- 四、案例三:配置Logback
一、前言
在開發 Java 應用時,日志記錄是不可或缺的一部分。日志可以記錄應用的運行狀態、錯誤信息和調試信息,幫助開發者快速定位和解決問題。Spring Boot 項目默認集成了 SLF4J 和 Logback,使得日志配置變得簡單而靈活。本文將詳細介紹如何在 Spring Boot 項目中配置 SLF4J 和 Logback,包括基本的日志配置、日志文件的輸出路徑、日志級別、日志格式和環境區分配置。
日志的重要性
- 快速定位問題:通過分析日志,開發者可以迅速定位應用程序中的錯誤或性能問題。
- 確保合規性:許多行業要求應用程序符合特定標準,日志記錄了應用程序的運行狀態,便于審計和合規性檢查。
- 提高開發效率:日志記錄了應用程序的歷史行為,有助于快速復現問題并優化代碼。
日志框架介紹
門面模式(Facade Pattern)又稱為外觀模式
門面模式(Facade Pattern)又稱為外觀模式, 提供了一個統?的接口, ?來訪問?系統中的?群接口.
其主要特征是定義了?個高層接口, 讓子系統更容易使用。
門面模式主要包含2種角色:
- 外觀角色(Facade): 也稱門面角色,系統對外的統?接口.
- 子系統角色(SubSystem): 可以同時有?個或多個 SubSystem. 每個 SubSytem 都不是?個單獨的類,而是?個類的集合. SubSystem 并不知道 Facade 的存在, 對于 SubSystem 而言, Facade 只是另?個客戶端而已(即 Facade 對 SubSystem 透明)
比如去醫院看病,可能要去掛號, 門診, 化驗, 取藥, 讓患者或患者家屬覺得很復雜, 如果有提供接待人員, 只讓接待?員來處理, 就很方便。
日志級別分類
1.Trace:
最低級別的日志,追蹤, 指明程序運行軌跡,比DEBUG更細粒度的信息事件(除非有特殊用意,否則請使用DEBUG級別替代)
2.Debug
詳細調試信息,常用于調試過程中使用的調試信息
3.Info
一般信息或狀態更新,常用于提供程序運行的基本信息
4.Warning
警告性信息,常用于提醒可能的問題或性能優化建議
5.ERROR
錯誤信息, 級別較高的錯誤日志信息, 但仍然不影響系統的繼續運行。
6.FATAL
致命信息,表示需要立即被處理的系統級錯誤。
二、案例一:初識日志
- 引入依賴
Spring Boot 項目默認已經包含了 SLF4J 和 Logback 的依賴,如果你使用的是 Spring Initializr 初始化的項目,通常不需要額外添加依賴。如果你的項目中沒有這些依賴,可以在pom.xml
中添加如下依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId>
</dependency>
- 基本日志配置
Spring Boot 允許通過application.yml
或application.properties
文件進行簡單的日志配置。以下是一個基本的配置示例:
application.yml
logging:level:root: INFOcom.example.yourpackage: DEBUG # 你的項目包路徑file:name: application.logpattern:console: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"file: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"
application.properties
logging.level.root=INFO
logging.level.com.example.yourpackage=DEBUG # 你的項目包路徑
logging.file.name=application.log
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
以上配置將日志級別設置為INFO,并為你的項目包設置為DEBUG級別。同時,設置了日志文件的名稱和日志輸出的格式。
- 日志的打印
創建控制層類 LoggerController.java
注意創建的日志對象,Logger和LoggerFactory類都是來自于Slf4j包底下的類。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/logger")
public class LoggerController {// 要想打印日志的前提是要有一個日志對象,日志對象來自于LoggerFactory類中 // 創建日志對象private Logger logger= LoggerFactory.getLogger(LoggerController.class);//打印不同級別的日志@RequestMapping("/log")public String log(){logger.info("====日志內容=====");logger.trace("====日志內容=====");logger.debug("====日志內容=====");logger.error("====日志內容=====");logger.warn("====日志內容=====");return "打印日志";}
}
代碼運行結果:
因本項目端口為9000
故訪問路徑:http://localhost:9000/logger/log
- 日志持久化
以上的日志都是輸出在控制臺上的, 然而在線上環境中, 我們需要把日志保存下來, 以便出現問題之后追溯問題. 把日志保存下來就叫持久化。
日志持久化有兩種方式:
- 配置日志文件名
- 配置日志的存儲目錄
配置日志文件名:
yml配置
logging:file:# 在源目錄下創建日志文件name: log/log.log
配置日志的保存路徑
yml文件配置
logging:file:# 日志在指定路徑下面path: d/loggeController
三、案例二:使用Lombok輸出日志
上面創建日志對象的方式還是比較麻煩的,如果程序中的類比較多的話,每個類都需要創建一個日志對象,就很繁瑣,此時我們可以借助lombok中的**@Slf4j**注解來更簡單的輸出日志。
@RestController
@RequestMapping("/logger")
@Slf4j
public class LoggerController {// @Slf4j 等同于// private Logger log= LoggerFactory.getLogger(LoggerController.class);@RequestMapping("/log")public String log(){// 添加@Slf4j注解后,類會自動生成一個log對象log.info("====日志內容=====");log.trace("====日志內容=====");log.debug("====日志內容=====");log.error("====日志內容=====");log.warn("====日志內容=====");return "打印日志";}
}
四、案例三:配置Logback
Logback 是 SLF4J 的一個實現,提供了更強大的日志配置功能。你可以通過logback-spring.xml
文件進行更詳細的日志配置。以下是一個示例配置文件:
1、logback-spring.xml
<configuration><!-- 定義日志文件的路徑和名稱 --><property name="LOG_PATH" value="/var/log/yourapp" /><property name="LOG_FILE" value="${LOG_PATH}/application.log" /><!-- 控制臺日志輸出配置 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- 文件日志輸出配置 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_FILE}</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 日志文件的滾動策略 --><fileNamePattern>${LOG_PATH}/application-%d{yyyy-MM-dd}.log</fileNamePattern><maxHistory>30</maxHistory> <!-- 保留30天的日志文件 --></rollingPolicy><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- 指定日志級別 --><logger name="org.apache.ibatis" level="DEBUG"><appender-ref ref="FILE" /><appender-ref ref="STDOUT" /></logger><logger name="com.example.yourpackage" level="DEBUG"><appender-ref ref="FILE" /><appender-ref ref="STDOUT" /></logger><!-- 根日志級別 --><root level="INFO"><appender-ref ref="FILE" /><appender-ref ref="STDOUT" /></root>
</configuration>
2、環境區分配置
在實際項目中,不同環境(如開發環境、測試環境、生產環境)的日志配置需求可能會有所不同。Spring Boot 支持多配置文件來區分不同環境。你可以在src/main/resources
目錄下創建多個配置文件,例如:
application-dev.yml
:開發環境配置application-test.yml
:測試環境配置application-prod.yml
:生產環境配置
application-dev.yml
spring:config:activate:on-profile: devlogging:level:root: DEBUGcom.example.yourpackage: DEBUGfile:name: application-dev.logpattern:console: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"file: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"
application-test.yml
spring:config:activate:on-profile: testlogging:level:root: INFOcom.example.yourpackage: INFOfile:name: application-test.logpattern:console: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"file: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"
application-prod.yml
spring:config:activate:on-profile: prodlogging:level:root: WARNcom.example.yourpackage: INFOfile:path: /var/log/yourappname: application-prod.logpattern:console: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"file: "%d{yyyy-MM-dd HH:mm:ss} %thread %-5level %logger{36} - %msg%n"
啟動應用時,可以通過命令行參數指定使用哪個配置文件:
java -jar -Dspring.profiles.active=prod yourapp.jar
3、日志文件路徑權限
確保 Spring Boot 應用在服務器上有寫日志文件的權限。你可以通過以下命令檢查和修改目錄權限:
# 檢查目錄權限
ls -ld /var/log/yourapp# 修改目錄權限
sudo chown -R youruser:yourgroup /var/log/yourapp
sudo chmod -R 755 /var/log/yourapp
4、日志文件查看
啟動應用后,檢查日志文件是否正確生成并記錄了日志。你可以在服務器上使用以下命令查看日志文件:
# 查看日志文件
tail -f /var/log/yourapp/application-prod.log
5、使用自定義攔截器
如果你需要在日志中記錄特定的信息,例如 SQL 執行時間,可以使用自定義攔截器。以下是一個示例攔截器:
SqlTimingInterceptor.java
package com.example.yourpackage.interceptor;import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.plugin.*;import java.sql.Statement;
import java.util.Properties;@Intercepts(@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}))
public class SqlTimingInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {long start = System.currentTimeMillis();try {return invocation.proceed();} finally {long end = System.currentTimeMillis();long timeTaken = end - start;StatementHandler statementHandler = (StatementHandler) invocation.getTarget();String sql = (String) SystemMetaObject.forObject(statementHandler).getValue("delegate.boundSql.sql");Log log = Slf4jImpl.create(this.getClass());log.debug("SQL: " + sql);log.debug("執行時間: " + timeTaken + " ms");}}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 可以設置一些自定義屬性}
}
MyBatisConfig.java
package com.example.yourpackage.config;import com.example.yourpackage.interceptor.SqlTimingInterceptor;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DriverManagerDataSource;import javax.sql.DataSource;
import java.util.Properties;@Configuration
@MapperScan("com.example.yourpackage.mapper")
public class MyBatisConfig {@Beanpublic DataSource dataSource() {DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setDriverClassName("org.postgresql.Driver");dataSource.setUrl("jdbc:postgresql://localhost:5432/yourdb");dataSource.setUsername("yourusername");dataSource.setPassword("yourpassword");return dataSource;}@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));// 注冊攔截器SqlTimingInterceptor sqlTimingInterceptor = new SqlTimingInterceptor();Properties properties = new Properties();properties.setProperty("someProperty", "someValue"); // 根據需要設置攔截器屬性sqlTimingInterceptor.setProperties(properties);factoryBean.setPlugins(new Interceptor[]{sqlTimingInterceptor});return factoryBean.getObject();}
}