Logback AsyncAppender is not working for FileAppender with custom Layout implementation

1.5k Views Asked by At

Logback's AsyncAppender is not logging when we link it with FileAppender which uses custom layout implementation. I have used below FileAppender with custom implementation of com.myorg.log.MaskingPatternLayout under LayoutWrappingEncoder.

Below is the snippet of logback.xml file:

//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>

Below is the custom implementation of 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);
        }
    }

}

Expected is to log the events in log file asynchronously but no logs are getting generated in "log/async.log". But at the same time when I try to use FileAppender without custom layout then it works fine.

0

There are 0 best solutions below