在SLF4J中使用JSON日志记录时如何包含多个JSON字段?

时间:2018-08-18 21:19:20

标签: logback slf4j dropwizard structured-logging

我正在使用Dropwizard 1.3.2,该软件使用SLF4J通过Logback进行日志记录。我正在将要提取的日志写入ElasticSearch,所以我认为我将使用JSON日志记录并制作一些Kibana仪表板。但是我真的希望每个日志消息有多个JSON项-如果我要记录具有十个字段的状态更新,则理想情况下,我希望记录该对象并使JSON字段显示为JSON日志中的顶级条目。我确实可以使MDC正常工作,但这非常笨拙,并且无法展平物体。

事实证明这很困难!我怎样才能做到这一点?我已经用JSON登录了​​,但是我不能很好地记录多个JSON字段!

我已经完成的事情:

我的Dropwizard配置具有此附加器:

  appenders:
    - type: console
      target: stdout
      layout:
        type: json
        timestampFormat: "ISO_INSTANT"
        prettyPrint: false
        appendLineSeparator: true
        additionalFields:
          keyOne: "value one"
          keyTwo: "value two"
        flattenMdc: true

将显示其他字段,但是这些值似乎在配置文件中是固定的,并且不会更改。有一个“ customFieldNames”,但没有有关如何使用它的文档,并且无论我放在那儿,我都会遇到“没有从字符串值反序列化的字符串参数构造函数/工厂方法”错误。 (文档的示例值是“ @timestamp”,但没有说明,甚至会产生错误。他们也有示例,例如“((requestTime:request_time,userAgent:user_agent))”,但同样,没有记载,我什么也做不了类似的工作,我尝试过的所有操作都会产生上述错误。

我确实可以使MDC正常工作,但是将每个项目插入MDC然后清除它似乎很愚蠢。

我可以反序列化对象并将其记录为嵌套JSON,但这似乎也很奇怪。

我在此看到的所有答案都是古老的-有人在Dropwizard内如何做到这一点有什么建议吗?

1 个答案:

答案 0 :(得分:0)

您可以使用custom logger factory在Dropwizard中显式使用logback,然后使用logstash-logback-encoder进行设置,并将其配置为写出到JSON附加程序。

JSON编码器可能如下所示:

<included>

    <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
        <providers>
            <pattern>
                <pattern>
                    {
                      "id": "%uniqueId",
                      "relative_ns": "#asLong{%nanoTime}",
                      "tse_ms": "#asLong{%tse}",
                      "start_ms": "#asLong{%startTime}",
                      "cpu": "%cpu",
                      "mem": "%mem",
                      "load": "%loadavg"
                    }
                </pattern>
            </pattern>
            <timestamp>
                <!-- UTC is the best server consistent timezone -->
                <timeZone>${encoders.json.timeZone}</timeZone>
                <pattern>${encoders.json.timestampPattern}</pattern>
            </timestamp>
            <version/>
            <message/>
            <loggerName/>
            <threadName/>
            <logLevel/>
            <logLevelValue/><!-- numeric value is useful for filtering >= -->
            <stackHash/>
            <mdc/>
            <logstashMarkers/>
            <arguments/>
            <provider class="com.tersesystems.logback.exceptionmapping.json.ExceptionArgumentsProvider">
                <fieldName>exception</fieldName>
            </provider>

            <stackTrace>
                <!--
                  https://github.com/logstash/logstash-logback-encoder#customizing-stack-traces
                -->
                <throwableConverter class="net.logstash.logback.stacktrace.ShortenedThrowableConverter">
                    <rootCauseFirst>${encoders.json.shortenedThrowableConverter.rootCauseFirst}</rootCauseFirst>
                    <inlineHash>${encoders.json.shortenedThrowableConverter.inlineHash}</inlineHash>
                </throwableConverter>
            </stackTrace>
        </providers>
    </encoder>
</included>

File on Github

并产生如下输出:

{"id":"FfwJtsNHYSw6O0Qbm7EAAA","relative_ns":20921024,"tse_ms":1584163814965,"start_ms":null,"@timestamp":"2020-03-14T05:30:14.965Z","@version":"1","message":"Creating Pool for datasource 'logging'","logger_name":"play.api.db.HikariCPConnectionPool","thread_name":"play-dev-mode-akka.actor.default-dispatcher-7","level":"INFO","level_value":20000}