Java日志中如何通过SL4J配置或正则对JSON内邮箱进行脱敏?
在SL4J中对JSON日志里的邮箱进行全局脱敏方案
首先得明确:SL4J本身只是个日志门面,它不负责处理日志内容的具体逻辑,实际得看你用的底层日志实现(比如Logback或者Log4j2)。你说的简单字符串替换没法全局落地是对的——总不能每个打日志的地方都手动加替换逻辑,最好的方式是通过底层日志框架的扩展来实现全局脱敏,下面给你两个可行的方案:
方案1:自定义日志转换器(精准全局脱敏,推荐)
这个方案适合需要精准定位JSON中特定字段的场景,比如你只需要脱敏clauses里attribute为email对应的values数组里的邮箱。以最常用的Logback为例:
步骤1:编写自定义转换器
写一个继承自ClassicConverter的类,负责解析JSON日志,找到目标邮箱并脱敏:
import ch.qos.logback.classic.pattern.ClassicConverter; import ch.qos.logback.classic.spi.ILoggingEvent; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import java.util.regex.Matcher; import java.util.regex.Pattern; public class EmailDesensitizingConverter extends ClassicConverter { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); // 匹配邮箱,保留前3位和后3位,中间脱敏 private static final Pattern EMAIL_MASK_PATTERN = Pattern.compile("(\\w{3}).*?@.*?(\\w{3})$"); @Override public String convert(ILoggingEvent event) { String originalLog = event.getMessage(); try { JsonNode root = OBJECT_MAPPER.readTree(originalLog); // 按照你的JSON结构定位到目标clause节点 JsonNode clausesNode = root.path("any_key").path("rules").get(0).path("clauses").get(0); // 先确认当前clause的attribute是email,避免误处理其他字段 if ("email".equals(clausesNode.path("attribute").asText())) { JsonNode valuesArray = clausesNode.path("values"); if (valuesArray.isArray()) { ObjectNode clauseObject = (ObjectNode) clausesNode; for (int i = 0; i < valuesArray.size(); i++) { String email = valuesArray.get(i).asText(); Matcher matcher = EMAIL_MASK_PATTERN.matcher(email); if (matcher.find()) { String maskedEmail = matcher.replaceFirst("$1*******@******$2"); clauseObject.putArray("values").set(i, OBJECT_MAPPER.valueToTree(maskedEmail)); } } } } return OBJECT_MAPPER.writeValueAsString(root); } catch (Exception e) { // 解析失败时返回原日志,防止影响业务正常日志输出 return originalLog; } } }
步骤2:在Logback配置中启用转换器
修改你的logback.xml,添加转换器规则并在输出格式中使用:
<configuration> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <!-- 用自定义的转换器替换原有的%msg --> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %emailDesensitize%n</pattern> <!-- 注册转换器 --> <conversionRule conversionWord="emailDesensitize" converterClass="com.your.package.EmailDesensitizingConverter"/> </encoder> </appender> <root level="info"> <appender-ref ref="CONSOLE"/> </root> </configuration>
如果用的是Log4j2,思路类似,只需要写一个继承PatternConverter的类,然后在log4j2.xml中配置即可。
方案2:全局正则替换(简单但可能误匹配)
如果你的日志里所有邮箱都需要脱敏,不需要精准定位JSON字段,可以直接用日志框架自带的替换功能。还是以Logback为例,修改logback.xml的encoder pattern:
<encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %replace(%msg){'(\w{3}).*?@.*?(\w{3})$', '$1*******@******$2'}%n</pattern> </encoder>
这个方式不需要写代码,但要注意:它会匹配日志消息中所有符合正则的邮箱字符串,不管是不是在你需要的JSON字段里,可能会误脱敏其他地方的邮箱,适合日志格式比较单一的场景。
最后再强调下:SL4J本身没有提供直接修改日志内容的配置,必须依赖底层的日志实现来做。上面两个方案都是全局生效的,不需要修改业务代码里的日志输出逻辑,完美解决你说的“无法全面落地”的问题。
内容的提问来源于stack exchange,提问作者Bush
相关产品推荐
相关产品推荐

