如何修正正则表达式,实现请求日志中cardNo前16位数字掩码
日志cardNo字段掩码方案修正
问题背景
需要对日志中请求的cardNo字段值进行掩码处理,保留最后4位,其余部分替换为X。cardNo的出现形式包含以下场景(冒号两侧可能存在空格):
"cardNo":"10929291929312911131"(cardNo:"10929291929312911131",cardType:"CREDIT")"cardNo" : "10929291929312911131"creditCardData(cardNo: "10929291929312911131",cardType:"CREDIT")
修正后的完整代码
import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.logging.log4j.core.*; import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; @Plugin(name = "LogMaskingConverter", category = "Converter") @ConverterKeys({ "mask" }) public class LogMaskingConverter extends LogEventPatternConverter { // 匹配cardNo的所有出现形式,捕获前缀、掩码部分、最后四位 private static final Pattern SENSITIVE_DATA_PATTERN = Pattern.compile("(\"?cardNo\"?)\\s*:\\s*\"?(\\d+)(\\d{4})\"?"); protected LogMaskingConverter(String name, String style) { super(name, style); } public static LogMaskingConverter newInstance(String[] options) { return new LogMaskingConverter("mask", null); } @Override public void format(LogEvent event, StringBuilder outputMessage) { String message = event.getMessage().getFormattedMessage(); String maskedMessage; try { maskedMessage = mask(message); } catch (Exception e) { maskedMessage = message; } outputMessage.append(maskedMessage); } private String mask(String message) { StringBuffer buffer = new StringBuffer(); maskMatcher(SENSITIVE_DATA_PATTERN.matcher(message), buffer); return buffer.toString(); } private StringBuffer maskMatcher(Matcher matcher, StringBuffer buffer) { while (matcher.find()) { String prefix = matcher.group(1); String maskedSection = matcher.group(2); // 生成与掩码部分等长度的X String xReplacement = "X".repeat(maskedSection.length()); String lastFourDigits = matcher.group(3); // 保留原格式的引号 boolean hasQuotes = matcher.group().contains("\""); String replacement = prefix + ": "; if (hasQuotes) { replacement += "\"" + xReplacement + lastFourDigits + "\""; } else { replacement += xReplacement + lastFourDigits; } matcher.appendReplacement(buffer, replacement); } matcher.appendTail(buffer); return buffer; } }
关键修正说明
正则表达式修正
- 正则
("?cardNo"?)\s*:\s*"?(\d+)(\d{4})"?:("?cardNo"?):捕获带/不带引号的cardNo前缀\s*:\s*:匹配冒号两侧任意数量的空格"?(\d+)(\d{4})"?:捕获卡号中除最后4位的部分(\d+)和最后4位(\d{4}),同时兼容卡号带/不带引号的情况
- 正则
动态掩码逻辑
- 不再使用固定数量的
X,而是根据卡号需要掩码的部分长度动态生成对应数量的X,适配不同长度的卡号 - 保留原日志中
cardNo字段的引号格式,确保日志格式一致性
- 不再使用固定数量的
代码语法修正
- 修正了类继承的拼写错误:
extend改为extends - 修正了注解拼写错误:
ConvertorKeys改为ConverterKeys,category = "Convertor"改为category = "Converter" - 修正了
newInstance方法中不必要的Thread.currentThread().getName()参数,替换为null符合父类构造要求
- 修正了类继承的拼写错误:
内容的提问来源于stack exchange,提问作者kselvan9000
相关产品推荐
相关产品推荐

