Logback - Layout & Pattern in logback.xml

拟墨画扇 提交于 2021-02-07 20:10:25

问题


I am using logback with slf4j for logging in Spring Boot application. I have created a custom layout class because all log statements are to be wrapped as a json. I have configured the logback-spring.xml as show below to take the custom layout. It works!

Issue is I am unable to apply the pattern. Only either the layout works (or) the pattern. What I want is always on log, go to layout class and then apply the pattern before logging.

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${user.home}/logs/sample.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>${user.home}/logs/sample_%d{yyyy-MM-dd}.%i.log</fileNamePattern>

        <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>10MB</maxFileSize>
        </timeBasedFileNamingAndTriggeringPolicy>
        <!-- how many days to keep the files -->
        <maxHistory>30</maxHistory>
    </rollingPolicy>

    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <layout class="com.test.test.payment.core.logging.SampleLogLayout" >
        </layout>
    </encoder>
    *<!-- <encoder>
        <charset>UTF-8</charset>
        <Pattern>{"@timestamp": "%d{yyyy-MM-dd HH:mm:ss.SSS}", "priority": "%p", "application": "payment",
            "class": "%C", "file": "%F:%L", "payload": %m }%n
        </Pattern>
    </encoder>-->*
</appender>

Here's the SampleLogLayout class:

public class SampleLogLayout extends LayoutBase<LoggingEvent> {

    @Override
    public String doLayout(LoggingEvent event) {

        String renderedMessage = event.getMessage();

        if (!isJson(renderedMessage)) {
            Throwable throwable = null;

            if (event.getLevel().equals(Level.ERROR) || event.getLevel().equals(Level.WARN)) {

            final IThrowableProxy throwableProxy = event.getThrowableProxy();
            if ((throwableProxy != null) && (throwableProxy instanceof ThrowableProxy)) {
                ThrowableProxy proxy = (ThrowableProxy) throwableProxy;
                throwable = proxy.getThrowable();
            }
            String message = LogErrorMessage.create(CommonCoreErrors.GENERIC_ERROR)
                    .message(renderedMessage).exception(throwable).build();

            return message;
        } else {
                return LogMessage.create(renderedMessage).build();
        }

        }
        return renderedMessage;
    }

    private boolean isJson(String msg) {
        if (null == msg) {
            return false;
        } else {
            return msg.startsWith("{") && msg.endsWith("}");
        }
    }
}

回答1:


I started to reproduce this in order to provide a complete solution but the absence of LogMessage and LogErrorMessage made that a bit tricky.

However, it looks to me like you just want to log in JSON format, not just the message but also the metadata such as timestamp, priority etc.

This can be achieved by using the JsonLayout. Here's an example of the layout configuration:

<layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
    <jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
        <prettyPrint>false</prettyPrint>
    </jsonFormatter>
    <timestampFormat>yyyy-MM-dd' 'HH:mm:ss.SSS</timestampFormat>
    <appendLineSeparator>true</appendLineSeparator>
    <includeContextName>false</includeContextName>
</layout>

With that configuration the following log invocation ...

logger.info("{\"a\": 1, \"b\": 2}");

... will emit:

{"timestamp":"2017-10-05 10:51:34.610","level":"INFO","thread":"main","logger":"com.stackoverflow.logback.LogbackTest","message":"{\"a\": 1, \"b\": 2}"} 

You can include MDC too, for example ...

MDC.put("application", "payment");
logger.info("{\"a\": 1, \"b\": 2}");

... will emit:

{"timestamp":"2017-10-05 10:52:56.088","level":"INFO","thread":"main","mdc":{"application":"payment"},"logger":"com.stackoverflow.logback.LogbackTest","message":"{\"a\": 1, \"b\": 2}"}

That's quite close to your desired output and JsonLayout is extensible so you could ...

  • Override toJsonMap() to change names of the keys e.g. replace timestamp with @timestamp, replace message with payload
  • Implement addCustomDataToJsonMap() to add other key:value pairs to the log event

So, I think you could achieve your desired output using the pre-existing JsonLayout rather than writing your own.

More details on Logback JSON extensions here.

The Maven coordinates are:

<dependency>
    <groupId>ch.qos.logback.contrib</groupId>
    <artifactId>logback-json-classic</artifactId>
    <version>0.1.5</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback.contrib</groupId>
    <artifactId>logback-json-core</artifactId>
    <version>0.1.5</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback.contrib</groupId>
    <artifactId>logback-jackson</artifactId>
    <version>0.1.5</version>
</dependency>


来源:https://stackoverflow.com/questions/46560939/logback-layout-pattern-in-logback-xml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!