自定义PatternLayoutEncoder
package com.logback;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class LogbackPatternLayoutEncoder extends PatternLayoutEncoder {
private LogbackReplaces replaces;
private Boolean sensitive = false;
@Override
public void start() {
LogbackPatternLayout patternLayout = new LogbackPatternLayout(replaces, sensitive);
patternLayout.setContext(context);
patternLayout.setPattern(this.getPattern());
patternLayout.setOutputPatternAsHeader(outputPatternAsHeader);
patternLayout.start();
this.layout = patternLayout;
started = true;
}
public boolean isSensitive() {
return sensitive;
}
public void setSensitive(boolean sensitive) {
this.sensitive = sensitive;
}
public LogbackReplaces getReplaces() {
return replaces;
}
public void setReplaces(LogbackReplaces replaces) {
this.replaces = replaces;
}
@Slf4j
public static class LogbackPatternLayout extends PatternLayout {
private LogbackReplaces replaces;
private Boolean sensitive;
public LogbackPatternLayout(LogbackReplaces replaces, Boolean sensitive) {
super();
this.replaces = replaces;
this.sensitive = sensitive;
}
@Override
public String doLayout(ILoggingEvent event) {
String msg = super.doLayout(event);
return this.buildSensitiveMsg(msg);
}
public String buildSensitiveMsg(String msg) {
if (sensitive == null || !sensitive) {
return msg;
}
if (this.replaces == null || this.replaces.getReplace() == null || this.replaces.getReplace().isEmpty()) {
log.error("日志脱敏开启,但未配置脱敏规则,请检查配置后重试");
return msg;
}
String sensitiveMsg = msg;
for (RegexReplacement replace : this.replaces.getReplace()) {
sensitiveMsg = replace.format(sensitiveMsg);
}
return sensitiveMsg;
}
}
public static class LogbackReplaces {
private List<RegexReplacement> replace = new ArrayList<>();
public void addReplace(RegexReplacement replacement) {
replace.add(replacement);
}
public List<RegexReplacement> getReplace() {
return replace;
}
public void setReplace(List<RegexReplacement> replace) {
this.replace = replace;
}
}
public static class RegexReplacement {
private Pattern regex;
private String replacement;
public String format(final String msg) {
return regex.matcher(msg).replaceAll(replacement);
}
public Pattern getRegex() {
return regex;
}
public void setRegex(String regex) {
this.regex = Pattern.compile(regex);
}
public String getReplacement() {
return replacement;
}
public void setReplacement(String replacement) {
this.replacement = replacement;
}
}
}
配置logback.xml
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="com.logback.LogbackPatternLayoutEncoder">
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
<sensitive>true</sensitive>
<replaces>
<replace>
<regex>
<![CDATA[
(mobile|手机号)(=|=\[|\":\"|:|:|='|':')(1)([3-9]{1}\d{1})(\d{4})(\d{4})(\]|\"|'|)
]]>
</regex>
<replacement>$1$2$3$4****$6$7</replacement>
</replace>
<replace>
<regex>
<![CDATA[
(password|密码|验证码)(=|=\[|\":\"|:|:|='|':')([a-z|A-Z|\d]{2,16})(\]|\"|'|)
]]>
</regex>
<replacement>$1$2******$4</replacement>
</replace>
</replaces>
</encoder>
</appender>
(password|密码|验证码)(=|=\[|\":\"|:|:|='|':')([a-z|A-Z|\d]{4,16})(\]|\"|'|)
<replacement>$1$2******$4</replacement>
$1 匹配第一个括号的内容
$1$2******$4 代表隐藏第三个括号匹配的全部内容
@Test
void test() {
log.info("{\"mobile\":\"15727331367\",\"password\":\"Abc123\"}");
}