在本文中,我們將探討如何在 Spring Boot 中使用 Mapped Diagnostic Context(MDC)來篩選單個請求相關的日誌信息。MDC 是 Logback 和 Log4j2 等日誌框架的一部分,它允許我們在日誌記錄過程中關聯上下文數據。通過這種方式,我們可以更有效地搜索和分析特定請求的日誌條目。
Spring Boot 中的 MDC 簡介
在 Spring Boot 中,你可以通過實現 `org.springframework.boot.actuate.trace.http.HttpTraceRepository` 接口來自定義 HTTP 日誌存儲庫,以便將請求特定的元數據保存在 MDC 中。默認情況下,Spring Boot 將跟蹤信息(如 URL、用戶代理、狀態碼等)附加到當前線程的 MDC。
配置 MDC 在 Spring Boot 中的應用
要啓用 Spring Boot 的 HTTP 追蹤功能,你需要在你的應用程序配置類上添加以下註解:
@Configuration(proxyBeanMethods = false)
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
// 其他配置代碼省略
}
這將會自動註冊一個 `TraceFilter`,該過濾器會在每個受支持的請求之前初始化一個跟蹤條目。然後,你可以在日誌記錄組件中訪問這些信息。
編寫日誌記錄組件以獲取 MDC 內容
爲了從 MDC 中讀取數據並在日誌消息中包含它們,你可以創建一個自定義的日誌記錄組件或擴展現有的日誌記錄庫。例如,如果你在使用 SLF4J + LogBack 作爲日誌框架,那麼你可以像這樣訪問 MDC 中的值:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* A custom log helper to access MDC values in logs.
*/
public final class CustomLogHelper {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomLogHelper.class);
private CustomLogHelper() {} // 避免實例化
/**
* Returns the current request's attributes as a string for logging purposes.
*/
public static String getCurrentRequestInfoForLogging() {
if (!RequestContextHolder.getRequestAttributes().isPresent()) {
return ""; // No active request, return empty string
}
try (ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()) {
HttpServletRequest httpServletRequest = servletRequestAttributes.getRequest();
StringBuilder sb = new StringBuilder();
sb.append("[").append(httpServletRequest.getMethod()).append("] ").append(httpServletRequest.getRequestURL());
sb.append(" - [").append(servletRequestAttributes.getLocalPort()).append("]");
return sb.toString();
} catch (Exception ex) {
LOGGER.error("Error while trying to retrieve current request info from MDC: {}", ex.getMessage(), ex);
return "";
}
}
}
現在,你可以在任何需要的地方調用 `CustomLogHelper#getCurrentRequestInfoForLogging()` 方法來獲取與當前請求相關的數據。
實際應用場景
假設我們有一個 REST API 端點,我們需要記錄所有請求的處理時間以及一些額外的上下文信息。我們可以按照如下方式進行日誌記錄:
@RestController
public class MyController {
private final CustomLogHelper logHelper;
public MyController(CustomLogHelper logHelper) {
this.logHelper = logHelper;
}
@GetMapping(value="/my-endpoint")
public ResponseEntity<Object> handleMyEndpoint(@NonNull @RequestParam(name="param1") String param1,
@NonNull @RequestParam(name="param2") Integer param2) throws Exception {
long startTime = System.nanoTime();
// Business logic goes here
Object result = calculateSomethingComplex(param1, param2);
long endTime = System.nanoTime();
String message = "Handling endpoint /my-endpoint with parameters: param1='%s', param2=%d took %d nanos";
LOGGER.info(message, param1, param2, endTime - startTime);
return ResponseEntity.ok(result);
}
// Other methods and business logic...
}
在這個例子中,每次調用 `/my-endpoint` 時,都會生成一條包含參數和處理時間的日誌消息。由於 MDC 中的數據是在請求生命週期中被維護的,所以即使我們的業務邏輯被異步任務或其他技術中斷,我們仍然可以確保日誌消息具有正確的上下文信息。
小結
使用 MDC 可以幫助你在 Spring Boot 應用程序中更高效地管理和查詢日誌數據。通過將請求特定的信息保存到 MDC 中,你可以輕鬆地將這些信息合併到你的日誌消息中,從而提高調試效率和日誌的可讀性。記住,正確設計和實施日誌策略對於監控應用程序的行爲和性能至關重要。