#StackBounty: #java #logback #asyncappender Logback AsyncAppender is not working for FileAppender with custom Layout implementation

Bounty: 50

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">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="com.myorg.log.MaskingPatternLayout">
                <pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="FILE_ASYNC_CUSTOM" />

    //Working with AsycnAppender
    <appender name="FILE_ASYNC_NO_CUSTOM" class="ch.qos.logback.core.FileAppender">
              <pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="FILE_ASYNC_NO_CUSTOM" />

Below is the custom implementation of PatternLayout.

    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();

    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)
                            , encode(matcher.group(4))));
        try {
        } catch (InterruptedException e) {
            log.error("Error on thread sleep: {}", e.getMessage());

        return maskedBody;

    private String getPatternToReplace(List<String> listToMask) {
        final StringBuilder sb = new StringBuilder();
            .filter(test -> !test.isEmpty())
            .ifPresent((List<String> list) -> {
                sb.append(list.stream().map(String::trim).collect(Collectors.joining("|", ""(", ")"")));
        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))

            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.

Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.