You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 10:01:15