SpringBoot與Logback整合,實現(xiàn)敏感信息日志脫敏并且異步高效寫入?功能
作者:Java知識日歷
?Logback 是一個強大且靈活的日志框架,適用于各種規(guī)模的應用程序。通過自定義 Appender,可以實現(xiàn)復雜的日志處理邏輯,如敏感信息脫敏和異步寫入,從而提升系統(tǒng)的安全性和性能。
Logback 是一個強大且靈活的日志框架,適用于各種規(guī)模的應用程序。通過自定義 Appender,可以實現(xiàn)復雜的日志處理邏輯,如敏感信息脫敏和異步寫入,從而提升系統(tǒng)的安全性和性能。
工作流程
圖片
為什么需要自定義 Appender?
在某些情況下,默認的 Appender 無法滿足特定需求,例如:
- 自動脫敏敏感信息。
- 異步處理日志以提高性能。
- 將日志發(fā)送到外部系統(tǒng)或服務。
代碼實操
<!-- Disruptor -->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.4</version>
</dependency>
<!-- Logback Classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
創(chuàng)建自定義Appender
創(chuàng)建一個名為SensitiveDataMaskingAppender的類,該類繼承自AppenderBase<ILoggingEvent>,并在其中使用Disruptor隊列進行異步處理。
package com.example.demo.logging;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import com.lmax.disruptor.*;
import com.lmax.disruptor.dsl.Disruptor;
import org.slf4j.MDC;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
publicclass SensitiveDataMaskingAppender extends AppenderBase<ILoggingEvent> {
// 正則表達式模式用于匹配身份證號碼
privatestaticfinal Pattern ID_CARD_PATTERN = Pattern.compile("\\d{15}(\\d{2}[A-Za-z])?");
// 正則表達式模式用于匹配手機號碼
privatestaticfinal Pattern PHONE_NUMBER_PATTERN = Pattern.compile("(\\+86)?(1[3-9]\\d{9})");
private RingBuffer<Event> ringBuffer;
@Override
public void start() {
super.start();
// 創(chuàng)建事件工廠
EventFactory<Event> factory = Event::new;
// 設置環(huán)形緩沖區(qū)大小,必須是2的冪
int bufferSize = 1024;
// 使用緩存線程池
Executor executor = Executors.newCachedThreadPool();
// 創(chuàng)建Disruptor實例
Disruptor<Event> disruptor = new Disruptor<>(factory, bufferSize, executor,
ProducerType.MULTI, new BusySpinWaitStrategy());
// 設置事件處理器
disruptor.handleEventsWith(new EventHandler<Event>() {
@Override
public void onEvent(Event event, long sequence, boolean endOfBatch) throws Exception {
// 脫敏日志消息
String logMessage = maskSensitiveData(event.getLogMessage());
// 打印脫敏后的日志消息到控制臺
System.out.println(logMessage);
}
});
// 獲取RingBuffer
ringBuffer = disruptor.getRingBuffer();
// 啟動Disruptor
disruptor.start();
}
@Override
protected void append(ILoggingEvent eventObject) {
// 獲取下一個序列號
long sequence = ringBuffer.next();
try {
// 根據(jù)序列號獲取事件對象
Event event = ringBuffer.get(sequence);
// 設置日志消息
event.setLogMessage(eventObject.getMessage());
} finally {
// 發(fā)布事件
ringBuffer.publish(sequence);
}
}
/**
* 脫敏日志消息中的敏感信息
* @param message 日志消息
* @return 脫敏后的日志消息
*/
private String maskSensitiveData(String message) {
Matcher idCardMatcher = ID_CARD_PATTERN.matcher(message);
while (idCardMatcher.find()) {
// 替換身份證號碼中間部分為星號
String maskedIdCard = idCardMatcher.group().substring(0, 6) + "********" + idCardMatcher.group().substring(14);
message = message.replace(idCardMatcher.group(), maskedIdCard);
}
Matcher phoneNumberMatcher = PHONE_NUMBER_PATTERN.matcher(message);
while (phoneNumberMatcher.find()) {
// 替換手機號碼中間部分為星號
String maskedPhoneNumber = phoneNumberMatcher.group().substring(0, 3) + "****" + phoneNumberMatcher.group().substring(7);
message = message.replace(phoneNumberMatcher.group(), maskedPhoneNumber);
}
return message;
}
// 定義事件類
privatestaticclass Event {
private String logMessage;
public String getLogMessage() {
return logMessage;
}
public void setLogMessage(String logMessage) {
this.logMessage = logMessage;
}
}
}
配置Logback使用自定義Appender
在src/main/resources/logback-spring.xml文件中配置自定義appender:
<configuration>
<!-- 自定義Appender配置 -->
<appender name="SENSITIVE_MASKING_APPENDER" class="com.example.demo.logging.SensitiveDataMaskingAppender">
</appender>
<!-- 根Logger配置 -->
<root level="info">
<appender-ref ref="SENSITIVE_MASKING_APPENDER"/>
</root>
</configuration>
創(chuàng)建Controller、Service和Repository層
Controller層
創(chuàng)建一個簡單的控制器來測試日志記錄功能。
package com.example.demo.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
publicclass UserController {
// 獲取日志記錄器
privatestaticfinal Logger logger = LoggerFactory.getLogger(UserController.class);
/**
* 處理/user請求,記錄用戶信息并返回響應
* @param idCard 用戶身份證號碼
* @param phoneNumber 用戶手機號碼
* @return 響應字符串
*/
@GetMapping("/user")
public String getUserInfo(@RequestParam String idCard, @RequestParam String phoneNumber) {
// 記錄用戶信息到日志
logger.info("User Info - ID Card: {}, Phone Number: {}", idCard, phoneNumber);
return"User info logged";
}
}
啟動類
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
測試
curl "http://localhost:8080/user?idCard=123456123456123456&phnotallow=13800138000"
控制臺日志
User Info - ID Card: 123456********56, Phone Number: 138****8000
責任編輯:武曉燕
來源:
Java知識日歷