API以Json格式记录

kir*_*ran 8 logging json logback mdc

我想将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" : "...."
  ]
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:

使用Logback,如何记录嵌套字段(例如上面示例中的标题,标签,requestPaylod),作为json子文档.我尝试过MDC,但它仅限于'String,String'的Map,并将第一级之后的所有字段视为String.

我讨厌为此编写我的自定义记录器,并希望使用成熟的日志记录框架(logback/log4j)的优点来控制日志记录级别,时间戳记日志事件等.

gly*_*ing 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>
Run Code Online (Sandbox Code Playgroud)

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

MDC.put("header1", "headerValue1");
logger.info("hello!");
logger.info("good bye!");
Run Code Online (Sandbox Code Playgroud)

...使用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"}
Run Code Online (Sandbox Code Playgroud)

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

编辑1:解决您的回复(“我的问题更多的是如何实现提到的json子文档/嵌套。MDC仅限于映射”)...您可以将复杂的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!");
Run Code Online (Sandbox Code Playgroud)

将产生以下输出(其中 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"}
Run Code Online (Sandbox Code Playgroud)