import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Node;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.AbstractStringLayout;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.pattern.RegexReplacement;
import java.nio.charset.Charset;
@Plugin(name = "MyPatternLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
public class MyPatternLayout extends AbstractStringLayout {
private PatternLayout patternLayout;
private Boolean sensitive;
private RegexReplacement[] replaces;
protected MyPatternLayout(Charset charset, String pattern, Boolean sensitive, RegexReplacement[] replaces) {
super(charset);
patternLayout = PatternLayout.newBuilder().withPattern(pattern).build();
this.sensitive = sensitive;
this.replaces = replaces;
}
/**
* 插件构造工厂方法
*
* @param pattern 输出pattern
* @param charset 字符集
* @param sensitive 是否开启脱敏
* @param replaces 脱敏规则
* @return Layout<String>
*/
@PluginFactory
public static Layout<String> createLayout(@PluginAttribute(value = "pattern") final String pattern,
@PluginAttribute(value = "charset", defaultString = "UTF-8") final Charset charset,
@PluginAttribute(value = "sensitive") final Boolean sensitive,
@PluginElement("replace") final RegexReplacement[] replaces) {
return new MyPatternLayout(charset, pattern, sensitive, replaces);
}
@Override
public String toSerializable(LogEvent event) {
// 原日志信息
String msg = this.patternLayout.toSerializable(event);
if (Boolean.FALSE.equals(this.sensitive)) {
// 不脱敏,直接返回
return msg;
}
if (this.replaces == null || this.replaces.length == 0) {
throw new RuntimeException("未配置脱敏规则,请检查配置重试");
}
for (RegexReplacement replace : this.replaces) {
// 遍历脱敏正则 & 替换敏感数据
msg = replace.format(msg);
}
// 脱敏后的日志
return msg;
}
}
以下预设了8中常见规则,请自行根据实际情况修改
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<properties>
<!-- 文件输出格式 -->
<property name="PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} %5level --- [%t] %c : %msg%n</property>
</properties>
<appenders>
<!-- 日志打印到控制台Appender -->
<Console name="CONSOLE" target="system_out">
<MyPatternLayout pattern="${PATTERN}" sensitive="true">
<replace>
<!-- 11位的手机号:保留前3后4 -->
<regex>
<![CDATA[
(mobile|手机号)(=|=\[|\":\"|:|:|=')(1)([3-9]{2})(\d{4})(\d{4})(\]|\"|'|)
]]>
</regex>
<replacement>$1$2$3$4****$6$7</replacement>
</replace>
<replace>
<!-- 固定电话:XXXX-XXXXXXXX或XXX-XXXXXXXX,保留区号+前2后2 -->
<regex>
<![CDATA[
(tel|座机)(=|=\[|\":\"|:|:|=')([\d]{3,4}-)(\d{2})(\d{4})(\d{2})(\]|\"|'|)
]]>
</regex>
<replacement>$1$2$3$4****$6$7</replacement>
</replace>
<replace>
<!-- 地址:汉字+字母+数字+下划线+中划线,留前3个汉字 -->
<regex>
<![CDATA[
(地址|住址|address)(=|=\[|\":\"|:|:|=')([\u4e00-\u9fa5]{3})(\w|[\u4e00-\u9fa5]|-)*(\]|\"|'|)
]]>
</regex>
<replacement>$1$2$3****$5</replacement>
</replace>
<replace>
<!-- 19位的卡号,保留后4 -->
<regex>
<![CDATA[
(cardNo|卡号)(=|=\[|\":\"|:|:|=')(\d{15})(\d{4})(\]|\"|'|)
]]>
</regex>
<replacement>$1$2***************$4$5</replacement>
</replace>
<replace>
<!-- 姓名,2-4汉字,留前1-->
<regex>
<![CDATA[
(name|姓名)(=|=\[|\":\"|:|:|=')([\u4e00-\u9fa5]{1})([\u4e00-\u9fa5]{1,3})(\]|\"|'|)
]]>
</regex>
<replacement>$1$2$3**$5</replacement>
</replace>
<replace>
<!-- 密码 6位数字,全* -->
<regex>
<![CDATA[
(password|密码|验证码)(=|=\[|\":\"|:|:|=')(\d{6})(\]|\"|'|)
]]>
</regex>
<replacement>$1$2******$4</replacement>
</replace>
<replace>
<!-- 身份证,18位(结尾为数字或X、x),保留前1后1 -->
<regex>
<![CDATA[
(身份证号|idCard)(=|=\[|\":\"|:|:|=')(\d{1})(\d{16})([\d|X|x]{1})(\]|\"|)
]]>
</regex>
<replacement>$1$2$3****************$5$6</replacement>
</replace>
<replace>
<!-- 邮箱,保留@前的前1后1 -->
<regex>
<![CDATA[
(\w{1})(\w*)(\w{1})@(\w+).com
]]>
</regex>
<replacement>$1****$3@$4.com</replacement>
</replace>
</MyPatternLayout>
</Console>
</appenders>
<loggers>
<!-- 控制台输出 -->
<root level="info">
<AppenderRef ref="CONSOLE"/>
</root>
</loggers>
</configuration>
Console使用了上一节中我们自己写的的MyPatternLayout,MyPatternLayout的两个属性pattern和sensitive,对应类MyPatternLayout的插件工厂方法的入参
MyPatternLayout节点的子节点replace(可多个)是我们配置的脱敏正则表达式