elastic / ecs-logging-java

https://www.elastic.co/guide/en/ecs-logging/java/current/intro.html
Apache License 2.0
139 stars 74 forks source link

Adding Layout to logback-ecs-encoder #144

Closed dgempiuc closed 2 months ago

dgempiuc commented 2 years ago

If there is an error in incoming requests, I am logging this request and some requests may contain sensitive information, such as password.

There is LayoutWrappingEncoder encoder on logback and I am able to add Layout that.

        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.custom.ecs.layout.MaskingPatternLayout">
                <maskPattern>\"oldPassword\"\s*:\s*\"(.*?)\"</maskPattern> <!-- password pattern -->
                <maskPattern>\"newPassword\"\s*:\s*\"(.*?)\"</maskPattern> <!-- password pattern -->
                <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            </layout>
        </encoder>

payload={ "newPassword": "****\", "oldPassword": "****", "smsCode": "123456" }

But, I am using EcsEncoder in production environment, but there is no option to add Layout in this encoder. So, I can't mask fields. Is there anyway to do that or is there any plan to add this?

dgempiuc commented 2 years ago

There is encode method on EcsEncoder and this method creates the log message to be written to the file.

    @Override
    public byte[] encode(ILoggingEvent event) {
        ...
        EcsJsonSerializer.serializeFormattedMessage(builder, event.getFormattedMessage());
        ...
     }

If we add Layout field in EcsEncoder class, we can use this in encode method.

public class EcsEncoder {

    ...
    protected Layout<ILoggingEvent> layout;

    @Override
    public byte[] encode(ILoggingEvent event) {
        StringBuilder builder = new StringBuilder();
        ...
        EcsJsonSerializer.serializeFormattedMessage(builder, this.layout.doLayout(event));
        ...
     }

     ...

    public Layout<ILoggingEvent> getLayout() {
        return this.layout;
    }

    public void setLayout(Layout<ILoggingEvent> layout) {
        this.layout = layout;
    }

}

So, we can use our custom Layout or predefined Layout.

        <encoder class="co.elastic.logging.logback.EcsEncoder">
            <serviceName>${springAppName:-}</serviceName>
            <layout class="org.custom.ecs.layout.MaskingEcsPatternLayout">
                <maskPattern>\"oldPassword\"\s*:\s*\"(.*?)\"</maskPattern> <!-- password pattern -->
                <maskPattern>\"newPassword\"\s*:\s*\"(.*?)\"</maskPattern> <!-- password pattern -->
                <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            </layout>
        </encoder>

Here is my custom Layout.

public class MaskingEcsPatternLayout extends PatternLayout {

    private Pattern multilinePattern;
    private List<String> maskPatterns = new ArrayList<>();

    public void addMaskPattern(String maskPattern) {
        maskPatterns.add(maskPattern);
        multilinePattern = Pattern.compile(maskPatterns.stream().collect(Collectors.joining("|")), Pattern.MULTILINE);
    }

    @Override
    public String doLayout(ILoggingEvent event) {
        return maskMessage(event.getFormattedMessage());
    }

    public String maskMessage(String message) {
        if (multilinePattern == null) {
            return message;
        }
        StringBuilder sb = new StringBuilder(message);
        Matcher matcher = multilinePattern.matcher(sb);
        while (matcher.find()) {
            IntStream.rangeClosed(1, matcher.groupCount()).forEach(group -> {
                if (matcher.group(group) != null) {
                    IntStream.range(matcher.start(group), matcher.end(group)).forEach(i -> sb.setCharAt(i, '*'));
                }
            });
        }
        return sb.toString();
    }

}
dgempiuc commented 2 years ago

created pr https://github.com/elastic/ecs-logging-java/pull/145

Tokimimo commented 1 year ago

Any chance such a function will be added? Or am I maybe missing something to achieve the above with the current encoder or available resources?

michalgutkowski commented 3 months ago

@Tokimimo IMO it works as expected after recent changes in #145:

 <appender name="ECS_JSON_CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="co.elastic.logging.logback.EcsEncoder">
        <messageLayout class="ch.qos.logback.classic.PatternLayout">
            <pattern>[%d{HH:mm:ss.SSS}] %t %-5p %c  - %m%n %rEx{full, org.springframework}</pattern>
        </messageLayout>
    </encoder>
</appender>
rdifrango commented 2 months ago

This was closed by #220 which was built upon #145 and has since been merged. @felixbarny and @mgreau we should close this issue now that it's been resolved.