AsyncAppender
链接时, Logback的FileAppender
未记录。我在FileAppender下面使用了com.myorg.log.MaskingPatternLayout
下的LayoutWrappingEncoder
的自定义实现。
下面是logback.xml
文件的摘要:
//Not Working with AsycnAppender
<appender name="FILE_ASYNC_CUSTOM" class="ch.qos.logback.core.FileAppender">
<file>log/async.log</file>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="com.myorg.log.MaskingPatternLayout">
<patternsProperty>password,dateOfBirth</patternsProperty>
<pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</layout>
</encoder>
</appender>
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE_ASYNC_CUSTOM" />
</appender>
//Working with AsycnAppender
<appender name="FILE_ASYNC_NO_CUSTOM" class="ch.qos.logback.core.FileAppender">
<file>log/async.log</file>
<encoder>
<pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE_ASYNC_NO_CUSTOM" />
</appender>
下面是PatternLayout
的自定义实现。
@Slf4j
public class MaskingPatternLayout extends PatternLayout {
private String patternsProperty;
private Optional<Pattern> pattern;
public String getPatternsProperty() {
return patternsProperty;
}
public void setPatternsProperty(String patternsProperty) {
this.patternsProperty = patternsProperty;
if (this.patternsProperty != null) {
this.pattern = Optional.of(Pattern.compile(getPatternToReplace(Arrays.asList(patternsProperty.split(",")))));
} else {
this.pattern = Optional.empty();
}
}
@Override
public String doLayout(ILoggingEvent event) {
final StringBuilder message = new StringBuilder(super.doLayout(event));
String maskedBody = message.toString();
if (pattern.isPresent()) {
Matcher matcher = pattern.get().matcher(message);
while (matcher.find()) {
maskedBody = maskedBody.replaceAll(matcher.group(0)
, matcher.group(0)
.replace(matcher.group(4)
, encode(matcher.group(4))));
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
log.error("Error on thread sleep: {}", e.getMessage());
}
return maskedBody;
}
private String getPatternToReplace(List<String> listToMask) {
final StringBuilder sb = new StringBuilder();
Optional.ofNullable(listToMask)
.filter(test -> !test.isEmpty())
.ifPresent((List<String> list) -> {
sb.append(list.stream().map(String::trim).collect(Collectors.joining("|", "\"(", ")\"")));
sb.append("(\\s)*:(\\s)*\"(.*?)\"");
});
return Optional.of(sb).map(StringBuilder::toString).filter(StringUtils::isNotEmpty).get();
}
private String encode(final CharSequence cs) {
try {
final byte[] csInUtf8 = Utf8.encode(cs);
final String csString = Utf8.decode(csInUtf8);
final String secret = "testing";
final Integer iteration = 10;
final Integer keyLength = 512;
final byte[] result = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512")
.generateSecret(new PBEKeySpec(csString.toCharArray(), secret.getBytes(StandardCharsets.UTF_8), iteration, keyLength))
.getEncoded();
return Base64.getEncoder().encodeToString(result);
} catch (final NoSuchAlgorithmException | InvalidKeySpecException ex) {
log.error("error: {}, value: {}", ex.getMessage(), cs, ex);
throw new RuntimeException(ex);
}
}
}
预期是将事件异步记录在日志文件中,但“ log / async.log”中没有生成任何日志。但是与此同时,当我尝试使用FileAppender
而不使用自定义布局时,效果很好。