SpringBoot与Logback整合,实现敏感信息日志脱敏并且异步高效写入功能

Logback 是一个强大且灵活的日志框架,适用于各种规模的应用程序。通过自定义 Appender
首页 新闻资讯 行业资讯 SpringBoot与Logback整合,实现敏感信息日志脱敏并且异步高效写入功能

Logback 是一个强大且灵活的日志框架,适用于各种规模的应用程序。通过自定义 Appender,可以实现复杂的日志处理逻辑,如敏感信息脱敏和异步写入,从而提升系统的安全性和性能。

工作流程

图片图片


为什么需要自定义 Appender?

在某些情况下,默认的 Appender 无法满足特定需求,例如:

  • 自动脱敏敏感信息。

  • 异步处理日志以提高性能。

  • 将日志发送到外部系统或服务。

代码实操

<!-- 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>

创建自定义Appender

创建一个名为SensitiveDataMaskingAppender的类,该类继承自AppenderBase<ILoggingEvent>,并在其中使用Disruptor队列进行异步处理。

package com.example.demo.logging;importch.qos.logback.classic.spi.ILoggingEvent;importch.qos.logback.core.AppenderBase;importcom.lmax.disruptor.*;importcom.lmax.disruptor.dsl.Disruptor;importorg.slf4j.MDC;importjava.util.concurrent.Executors;importjava.util.regex.Matcher;importjava.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;@Overridepublicvoidstart(){
        super.start();// 创建事件工厂EventFactory<Event>factory=Event::new;// 设置环形缓冲区大小,必须是2的幂intbufferSize=1024;// 使用缓存线程池Executor executor=Executors.newCachedThreadPool();// 创建Disruptor实例Disruptor<Event>disruptor=new Disruptor<>(factory,bufferSize,executor,ProducerType.MULTI,new BusySpinWaitStrategy());// 设置事件处理器disruptor.handleEventsWith(new EventHandler<Event>(){@Overridepublicvoid onEvent(Event event,long sequence,booleanendOfBatch)throws Exception {// 脱敏日志消息String logMessage=maskSensitiveData(event.getLogMessage());// 打印脱敏后的日志消息到控制台System.out.println(logMessage);}
        });// 获取RingBufferringBuffer=disruptor.getRingBuffer();// 启动Disruptordisruptor.start();}@Overrideprotected void append(ILoggingEvent eventObject){// 获取下一个序列号long sequence=ringBuffer.next();try {// 根据序列号获取事件对象Event event=ringBuffer.get(sequence);// 设置日志消息event.setLogMessage(eventObject.getMessage());} finally {// 发布事件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);}returnmessage;}// 定义事件类privatestaticclass Event {
        private String logMessage;publicString getLogMessage(){returnlogMessage;}publicvoid 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>

创建Controller、Service和Repository层

Controller层

创建一个简单的控制器来测试日志记录功能。

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
39    2025-03-04 08:40:28    日志 框架 程序