Logyn AsyncAppender не работает для FileAppender с пользовательской реализацией макета - PullRequest
7 голосов
/ 01 июля 2019

Logback's AsyncAppender не регистрирует, когда мы связываем его с 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 без пользовательского макета, он работает нормально.

...