【问题标题】:Logback - Layout & Pattern in logback.xmlLogback - logback.xml 中的布局和模式
【发布时间】:2026-02-14 04:40:01
【问题描述】:

我正在使用带有 slf4j 的 logback 来登录 Spring Boot 应用程序。我创建了一个自定义布局类,因为所有日志语句都将被包装为 json。我已将 logback-spring.xml 配置为如下所示以采用自定义布局。有用!

问题是我无法应用该模式。只有布局有效(或)模式。我想要的总是在日志中,进入布局类,然后在日志之前应用模式。

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

这是SampleLogLayout 类:

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

【问题讨论】:

  • 我想我们也需要看看这门课:com.test.test.payment.core.logging.SampleLogLayout
  • 是的,添加了我的 SampleLogLayout 类。基本上 LogErrorMessage.create() & LogMessage.create() 将消息转换为 JSON
  • 好的,这很有用。我仍然不清楚问题是什么。您是说您希望SampleLogLayout 发出带有模式的renderedMessage?也许添加 (1) 一个示例日志调用(以便我们可以看到 renderedMessage 的样子)和 (2) 所需的输出将有助于澄清事情。
  • 是的,你是对的 - 我们希望将 renderMessage 传递给模式。
  • 使用Layout的实际结果如下,{ "logType": "EXCEPTION", "message": "testing", "errorDetails": { "errorCode": "COMMON_600", "errorDescription": “一般错误”} }

标签: spring-boot logback


【解决方案1】:

我开始复制这个以提供完整的解决方案,但缺少 LogMessageLogErrorMessage 使得这有点棘手。

但是,在我看来,您只想以 JSON 格式登录,不仅是消息,还包括 timestamppriority 等元数据。

这可以通过使用JsonLayout 来实现。这是布局配置的示例:

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

使用该配置,以下日志调用...

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

... 将发出:

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

您也可以包含 MDC,例如 ...

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

... 将发出:

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

这与您想要的输出非常接近,JsonLayout 是可扩展的,因此您可以...

  • 覆盖 toJsonMap() 以更改键的名称,例如将timestamp 替换为@timestamp,将message 替换为payload
  • 实现addCustomDataToJsonMap() 以将其他键:值对添加到日志事件中

所以,我认为您可以使用预先存在的JsonLayout 来实现您想要的输出,而不是自己编写。

更多关于 Logback JSON 扩展的细节here

Maven 坐标为:

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

【讨论】:

  • 感谢故障!有用。我尝试使用 并且这也适用于扩展 ClassicConverter 的 JsonFormatLogConverter。我会选择你的解决方案。谢谢