Logback 和 JsonLayout:无法传递自定义字段

Yur*_*uri 8 logging spring logback logback-classic

我在 logback.xml 中将此配置放入 Spring Web 应用程序(无 Spring Boot)。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

     <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">

        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">             
            <layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
                <timestampFormat>yyyy-MM-dd'T'HH:mm:ss.SSSX</timestampFormat>
                <timestampFormatTimezoneId>Etc/UTC</timestampFormatTimezoneId>              
                <jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
                    <prettyPrint>true</prettyPrint>
                </jsonFormatter>
            </layout>            
            <customFields>{"appname":"foobar"}</customFields>            
        </encoder>                    
    </appender>

    <!-- LOG everything at INFO level -->
    <root level="INFO">
        <appender-ref ref="Console" />
    </root>

</configuration>
Run Code Online (Sandbox Code Playgroud)

JSON 布局工作正常,但不会打印“appname”:“foobar”这样的自定义字段:

{
  "timestamp" : "2020-06-10T14:55:25.534Z",
  "level" : "INFO",
  "thread" : "Catalina-utility-1",
  "logger" : "org.springframework.web.servlet.DispatcherServlet",
  "message" : "FrameworkServlet 'dispatcher': initialization completed in 72 ms",
  "context" : "default"
}
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

解决方案

我使用了错误的库来满足我的需求:

  • Logback杰克逊
  • logback-json-经典

由于我需要通过 Logstash 处理日志,因此我更正了我的配置,如下所示:

pom.xml

<dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>net.logstash.logback</groupId>
                <artifactId>logstash-logback-encoder</artifactId>
                <version>6.4</version>
            </dependency>
Run Code Online (Sandbox Code Playgroud)

日志记录文件

<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <customFields>{"customer":"X", "appname":"Y", "environment":"dev"}</customFields>            
        </encoder>    
    </appender>
Run Code Online (Sandbox Code Playgroud)

现在效果很好。

mit*_*man 1

我只是偶然发现了这个问题,因为我遇到了同样的问题,并且我找到了一个解决方案,使用logback-jackson和logback-json-classic。

选项 1:通过映射诊断上下文按线程 ( MDC)

SLF4j 的映射诊断上下文是一个每线程键值存储,我们可以使用它来将自定义结构化数据写入日志输出。

MDC.put("customKey", "customValue");
Run Code Online (Sandbox Code Playgroud)

LogbackJsonLayout将自动在特殊的 JSON 对象下打印该值,mdc无需任何进一步配置。

{ [...], "mdc": {"customKey", "customValue"}} 
Run Code Online (Sandbox Code Playgroud)

请注意,MDC是按线程构造的,如果它为空,则不mdc会将任何字段打印到日志输出中。

选项 2:全局(适用于所有线程)

如果您希望自定义字段出现在 JSON 输出的根目录中,则需要创建一个扩展的自定义但简单的 Layout 类JsonLayout。JsonLayout为我们提供了一个addCustomDataToJsonMap我们可以重写的方法。

package com.mypackage;

import ch.qos.logback.contrib.json.classic.JsonLayout;

public class CustomJsonLayout extends JsonLayout {

  @Override
  protected void addCustomDataToJsonMap(Map<String, Object> map, ILoggingEvent event) {
    map.put("customKey", "customValue");
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,您只需告诉 Logback在您的文件中使用CustomJsonLayout而不是使用,并保持其余部分相同。JsonLayoutlogback.xml

<layout class="com.mypackage.CustomJsonLayout">
    ...
</layout>
Run Code Online (Sandbox Code Playgroud)

现在,任何日志消息都将具有以下输出:

{ ..., "customKey": "customValue"}
Run Code Online (Sandbox Code Playgroud)