spring boot log4j2 最佳實踐
阿新 • • 發佈:2021-10-17
日誌輸出整齊有序;
不同級別日誌採用不同顏色輸出,更加清晰直觀;
日誌輸出可帶有使用者標識或特定標識,有利於檢視同組的多個請求軌跡、排查問題;
不同環境採用不同配置,本地測試日誌只輸出到控制檯,其他環境日誌輸出到指定檔案;
線上日誌按天分割,歷史日誌按月壓縮存放,定期刪除之前日誌,便於排查問題,防止日誌累積達到磁碟上限;
警告錯誤日誌再單獨輸出到錯誤日誌檔案中,便於快速定位問題;
為什麼選擇 log4j2
Log4j2 使用了 LMAX Disruptor 庫。在多執行緒場景中,非同步 Logger 的吞吐量比 Log4j 1.x 和 Logback 高 18 倍,延遲低幾個數量級。如下是官網的效能對比:
上圖來源:https://logging.apache.org/log4j/2.x/performance.html
最終效果
- 日誌輸出整齊有序;
- 不同級別日誌採用不同顏色輸出,更加清晰直觀;
- 日誌輸出可帶有使用者標識或特定標識,有利於檢視同組的多個請求軌跡、排查問題;
- 不同環境採用不同配置,本地測試日誌只輸出到控制檯,其他環境日誌輸出到指定檔案;
- 線上日誌按天分割,歷史日誌按月壓縮存放,定期刪除之前日誌,便於排查問題,防止日誌累積達到磁碟上限;
- 警告錯誤日誌再單獨輸出到錯誤日誌檔案中,便於快速定位問題;
日誌效果圖
程式碼示例
maven 依賴
點選檢視程式碼
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <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> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>
注入標識過濾器
點選檢視程式碼
import org.slf4j.MDC; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class UidLogFilter extends OncePerRequestFilter { private static final String UID = "Uid"; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String uid = request.getHeader(UID); if (!StringUtils.hasLength(uid)){ uid = request.getParameter(UID); } /** * 將使用者標識放入日誌上下文中 */ MDC.put("uid", uid); filterChain.doFilter(request, response); } }
BestPracticeApplication
點選檢視程式碼
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@SpringBootApplication
public class BestPracticeApplication {
/**
* 根據請求引數輸出不同級別的日誌
*/
@GetMapping("/")
public String home(String level) {
String msg = "Hello World!";
try {
switch (level){
case "trace": log.trace(msg); break;
case "debug": log.debug(msg); break;
case "info": log.info(msg); break;
case "warn": log.warn(msg); break;
case "error": log.error(msg); break;
//帶引數的日誌輸出方式
default: log.error("未知的日誌級別: {}", level); break;
}
}catch (NullPointerException e){
//異常日誌輸出方式
log.error("日誌級別為空", e);
}
return msg;
}
@Bean
public UidLogFilter uidLogFilter(){
return new UidLogFilter();
}
static {
System.setProperty("log4j.skipJansi", "false");
}
public static void main(String[] args) {
SpringApplication.run(BestPracticeApplication.class, args);
}
}
application.yml
點選檢視程式碼
spring:
profiles:
active: local
---
#本地環境
spring:
config:
name: local
logging:
config: classpath:log4j2-local.xml
---
#測試環境
spring:
config:
name: test
---
#線上環境
spring:
config:
name: online
log4j2-local.xml
點選檢視程式碼
<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorInterval="30">
<Properties>
<Property name="LOG_PATTERN_LAYOUT">%d{HH:mm:ss,SSS} %highlight{[%-5.5level]}{STYLE=Logback} [%-5.5thread] %blue{[%-5.5X{uid}]} %cyan{[%-40.40c{1.}:%-4line]} - %msg%xEx%n</Property>
<Property name="DEFAULT_CHARSET">UTF-8</Property>
</Properties>
<Appenders>
<!-- 定義控制檯輸出 -->
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout charset="${DEFAULT_CHARSET}" pattern="${LOG_PATTERN_LAYOUT}"/>
</Console>
</Appenders>
<Loggers>
<!-- 包名以cn.learncoding 開頭的日誌輸出級別為TRACE -->
<Logger name="cn.learncoding" level="TRACE"/>
<!-- 預設日誌輸出級別為INFO -->
<Root level="INFO">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
log4j2.xml
點選檢視程式碼
<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorInterval="30">
<Properties>
<!-- ${sys:catalina.home:-.}/logs 表示 取系統變數catalina.home指向的目錄下面的logs目錄,如果沒有則取當前所在目錄下面的logs目錄 -->
<Property name="LOG_HOME">${sys:catalina.home:-.}/logs</Property>
<Property name="LOG_BACK_HOME">${sys:catalina.home:-.}/logs/backup</Property>
<!-- 日誌輸出格式 -->
<!-- %-5.5thread 表示最少長度為5,不足空格補齊,超出5則只保留後5位 -->
<!-- %highlight{[%-5.5level]}{STYLE=Logback} 表示此欄位使用Logback格式的高亮顏色展示,最少長度為5,不足空格補齊,超出5則只保留後5位 -->
<!-- %blue{[%-5.5X{uid}]} 表示此上下文欄位採用藍色進行輸出,最少長度為5,不足空格補齊,超出5則只保留後5位 -->
<Property name="LOG_PATTERN_LAYOUT">%d{HH:mm:ss,SSS} %highlight{[%-5.5level]}{STYLE=Logback} [%-5.5thread] %blue{[%-5.5X{uid}]} %cyan{[%-40.40c{1.}:%-4line]} - %msg%xEx%n </Property>
<Property name="DEFAULT_CHARSET">UTF-8</Property>
<Property name="ERROR_FILE_NAME">error</Property>
<Property name="INFO_FILE_NAME">info</Property>
</Properties>
<Appenders>
<!-- 配置日常日誌 歷史日誌按月存放,按天分割壓縮儲存-->
<RollingFile name="${INFO_FILE_NAME}" fileName="${LOG_HOME}/${INFO_FILE_NAME}.log" filePattern="${LOG_BACK_HOME}/$${date:yyyy-MM}/${INFO_FILE_NAME}-%d{yyyy-MM-dd}.log.gz" append="true">
<PatternLayout charset="${DEFAULT_CHARSET}" pattern="${LOG_PATTERN_LAYOUT}"/>
<Policies>
<!-- 基於時間的滾動策略,按天分割 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
<DefaultRolloverStrategy >
<!--刪除30天前的日誌-->
<Delete basePath="${LOG_BACK_HOME}" maxDepth="2">
<IfFileName glob="*/*.log.gz" />
<IfLastModified age="30d" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
<!-- 配置錯誤日誌 歷史日誌按月存放,按天分割壓縮儲存-->
<RollingFile name="${ERROR_FILE_NAME}" fileName="${LOG_HOME}/${ERROR_FILE_NAME}.log" filePattern="${LOG_BACK_HOME}/$${date:yyyy-MM}/${ERROR_FILE_NAME}-%d{yyyy-MM-dd}.log.gz" append="true">
<PatternLayout charset="${DEFAULT_CHARSET}" pattern="${LOG_PATTERN_LAYOUT}"/>
<Policies>
<!-- 基於時間的滾動策略,按天分割 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
<Filters>
<!--級別大於等於WARN的日誌可以寫入-->
<ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
</RollingFile>
</Appenders>
<Loggers>
<!-- 預設日誌輸出級別為INFO -->
<Root level="INFO">
<AppenderRef ref="${INFO_FILE_NAME}"/>
<AppenderRef ref="${ERROR_FILE_NAME}"/>
</Root>
</Loggers>
</Configuration>
本文來自部落格園,作者:crazy_dev,轉載請註明原文連結:https://www.cnblogs.com/crazy-dev/p/15399576.html