8

我想将 API 请求/响应记录为 json 格式。

预期的 LogEntry 类似于

{ 
 "timestamp" : "...",
 "level" : "DEBUG",
 "headers" : [
    "header1" : "value1",
    "header2" : "value2",
    "header3" : "value3"
 ],
 "requestPayload" : "<Request Json>"   // prefereablly as sub-document, worst case string is fine.   
 "labels" : [        //key fields which can be used for searching the logentry
     "searchField1" : "....",
     "searchField2" : "....",
     "searchField3" : "...."
  ]
}

我的问题是:

使用 Logback,如何将嵌套字段(例如,上例中的 headers、labels、requestPaylod)记录为 json 子文档。我尝试了 MDC,但它仅限于“字符串,字符串”的映射,并将第一级之后的所有字段都视为字符串。

我讨厌为此编写我的自定义记录器,并且想利用经过验证的日志记录框架(logback/log4j)的优点来控制日志记录级别、时间戳日志事件等。

4

2 回答 2

4

对于请求/响应日志记录,请尝试Logbooklogstash-logback-encoder。您将能够使用标记添加结构化内容。

为了在 JSON 结构中添加“您自己的”字段,我编写了一个您可能会觉得有趣的代码生成器,它添加了构建器支持:json-log-domain

于 2018-04-20T10:33:53.827 回答
2

你可以在任何 Logback appender中使用logback-contrib 。 JsonLayout例如:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <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>
    </layout>
</appender>

给定这样的日志语句...

MDC.put("header1", "headerValue1");
logger.info("hello!");
logger.info("good bye!");

... 的使用JsonLayout会导致 Logback 写成这样:

{"timestamp":"2017-08-15 09:06:41.813","level":"INFO","thread":"main","mdc":{"header1":"headerValue1"},"logger":"com.stackoverflow.logback.LogbackTest","message":"hello!","context":"default"}
{"timestamp":"2017-08-15 09:06:41.887","level":"INFO","thread":"main","mdc":{"header1":"headerValue1"},"logger":"com.stackoverflow.logback.LogbackTest","message":"good bye!","context":"default"}

我认为这符合将日志事件写入 JSON 文档的要求,同时仍保留 Logback 的行为,例如“控制日志记录级别、时间戳日志事件等”。有一些对更改 JSON 格式的内置支持(例如,您可以包含/排除上下文、记录器名称等),但 JsonLayout 类提供了一个扩展点,允许您通过扩展和覆盖来更改生成的 JSON 中的属性名称. JsonLayouttoJsonMap()

编辑 1:解决您的回复(“我的问题更多是关于如何实现所提到的 json 子文档/嵌套。MDC 仅限于 map of only”)...您可以将复杂的 MDC 值序列化为 JSON 并添加序列化的 JSON 表示到 MDC。例如:

    Map<String, Object> complexMdcValue = new HashMap<>();
    Map<String, Object> childMdcValue = new HashMap<>();
    childMdcValue.put("name", "Joe");
    childMdcValue.put("type", "Martian");
    complexMdcValue.put("child", childMdcValue);
    complexMdcValue.put("category", "etc");

    MDC.put("complexNestedValue", objectMapper.writeValueAsString(complexMdcValue));
    logger.info("hello!");

将产生此输出(其中 MVC 记录的键“complexNestedValue”包含子文档的 JSON):

{"timestamp":"2017-08-27 18:03:46.706","level":"INFO","thread":"main","mdc":{"complexNestedValue":"{\"category\":\"etc\",\"child\":{\"name\":\"Joe\",\"type\":\"Martian\"}}"},"logger":"com.stackoverflow.logback.LogbackTest","message":"hello!","context":"default"}
于 2017-08-15T08:11:37.317 回答