Загрузка данных
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MaskingPatternLayout extends PatternLayout {
private final List<ReplaceTemplate> replaceTemplates = new ArrayList<>();
private static final ObjectMapper objectMapper = new ObjectMapper();
public void setPatternsProperty(String patternsProperty) throws IOException {
Map<String, String> map = objectMapper.readValue(patternsProperty, HashMap.class);
for (Map.Entry<String, String> entry : map.entrySet()) {
if (entry.getValue().contains("~")) {
String[] s = entry.getValue().split("~");
int firstPartLength = Integer.valueOf(s[0]);
int lastPartLength = Integer.valueOf(s[2]);
String replaceString = s[1];
replaceTemplates.add(new ReplaceTemplate(Pattern.compile(entry.getKey()), replaceString, firstPartLength, lastPartLength));
} else {
replaceTemplates.add(new ReplaceTemplate(Pattern.compile(entry.getKey()), entry.getValue()));
}
}
}
@Override
public String doLayout(ILoggingEvent event) {
String msg = super.doLayout(event);
for (ReplaceTemplate replaceTemplate : replaceTemplates) {
Matcher matcher = replaceTemplate.getSourcePattern().matcher(msg);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
if (replaceTemplate.isSimpleReplace()) {
matcher.appendReplacement(sb, replaceTemplate.getReplaceString());
} else {
String group = matcher.group();
String s1 = group.substring(0, replaceTemplate.getFirstPartLength());
String s2 = group.substring(group.length() - replaceTemplate.getLastPartLength());
matcher.appendReplacement(sb, s1 + replaceTemplate.replaceString + s2);
}
}
matcher.appendTail(sb);
msg = sb.toString();
}
return msg;
}
//todo поля final и в record
private class ReplaceTemplate {
private Pattern sourcePattern;
private String replaceString;
private int firstPartLength;
private int lastPartLength;
private boolean simpleReplace;
public ReplaceTemplate(Pattern sourcePattern, String replaceString) {
this.sourcePattern = sourcePattern;
this.replaceString = replaceString;
this.simpleReplace = true;
}
public ReplaceTemplate(Pattern sourcePattern, String replaceString, int firstPartLength, int lastPartLength) {
this.sourcePattern = sourcePattern;
this.replaceString = replaceString;
this.firstPartLength = firstPartLength;
this.lastPartLength = lastPartLength;
this.simpleReplace = false;
}
public Pattern getSourcePattern() {
return sourcePattern;
}
public String getReplaceString() {
return replaceString;
}
public int getFirstPartLength() {
return firstPartLength;
}
public int getLastPartLength() {
return lastPartLength;
}
public boolean isSimpleReplace() {
return simpleReplace;
}
}
}
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="MaskingPatternLayout">
<patternsProperty>
<![CDATA[
{
"pan[ ]*[:][ ]*[\\d]*]" : "pan : ***]",
"PAN[ ]*****[:][ ]*****[\\d]*****]" : "PAN : ***]",
"pan[ ]*[=:][ ]*'[\\d]*'" : "11~**~5",
"pan[ ]*****[=:][ ]*****\"[\\d]*\"" : "11~**~5",
}
]]>
</patternsProperty>
<pattern>%date [%thread] %-5level %logger:%line - %message %mdc{jobKeyName} %n</pattern>
</layout>
</encoder>
</appender>
//todo AsyncAppender -- может и не потребоваться, но нужно потестить
<appender name="console_ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="console"/>
<queueSize>1000</queueSize>
<includeCallerData>true</includeCallerData>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
</root>