SpringBootのログをjson形式で出力する

# 参考
[JSON Logging for Spring Boot](http://development.wombatsecurity.com/development/2018/12/20/json-logging-for-spring-boot/)
以降、上記の記事に沿って実装した内容を載せています
上記の記事の方が情報量が多いので英語が苦でなければそちらを参照することをお勧めします


# 実行環境
* Java12
* SpirngBoot 2.1.7.RELEASE
* Gradle 5.6

# 準備
依存関係にlogstashを追加

```build.gradle
dependencies {
	implementation 'net.logstash.logback:logstash-logback-encoder:6.1'
}
```

logbackの設定を追加

```src/main/resources/logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property resource="application.yml" />
    <contextName>${spring.application.name}</contextName>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <timestamp>
                    <fieldName>timeStamp</fieldName>
                    <timeZone>UTC</timeZone>
                </timestamp>
                <loggerName>
                    <fieldName>logger</fieldName>
                </loggerName>
                <logLevel>
                    <fieldName>level</fieldName>
                </logLevel>
                <threadName>
                    <fieldName>thread</fieldName>
                </threadName>
                <mdc />
                <message>
                    <fieldName>message</fieldName>
                </message>
                <arguments>
                    <includeNonStructuredArguments>false</includeNonStructuredArguments>
                </arguments>
                <stackTrace>
                    <fieldName>stack</fieldName>
                </stackTrace>
            </providers>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>
```

# 実装
ControllerクラスでINFOログを出力する例
※Loggerの取得はlombokの@Slf4jアノテーションにおまかせ

```TestController.java
package com.exsample.controller;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import static net.logstash.logback.argument.StructuredArguments.v;

@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
    @GetMapping
    public void get() {
        MDC.put("MDC key","MDC value");
        log.info("JSON Log",v("arg key","arg value"));
    }
}
```

# 結果
以下のログが出力される

```
{"timeStamp":"2019-08-28T08:52:22.173Z","logger":"com.exsample.controller.TestController","level":"INFO","thread":"main","MDC key":"MDC value","message":"JSON Log","arg key":"arg value"}
```

# 補足
* `logback-spring.xml`の`<encoder>`タグ内で設定した内容が上から順に出力される

```（抜粋）logback-spring.xml
<providers>
  <timestamp>
    <fieldName>timeStamp</fieldName>
    <timeZone>UTC</timeZone>
  </timestamp>
  <loggerName>
    <fieldName>logger</fieldName>
  </loggerName>
  <logLevel>
    <fieldName>level</fieldName>
  </logLevel>
  <threadName>
    <fieldName>thread</fieldName>
  </threadName>
  <mdc />
  <message>
    <fieldName>message</fieldName>
  </message>
  <arguments>
    <includeNonStructuredArguments>false</includeNonStructuredArguments>
  </arguments>
  <stackTrace>
    <fieldName>stack</fieldName>
  </stackTrace>
</providers>
```

```json:ログ内容
{
  "timeStamp": "2019-08-28T08:52:22.173Z",
  "logger": "com.exsample.controller.TestController",
  "level": "INFO",
  "thread": "main",
  "MDC key": "MDC value",
  "message": "JSON Log",
  "arg key": "arg value"
}
```

* `MDC.put()`した内容は`<mdc />`タグの位置に出力される

```（抜粋）TestController.java
MDC.put("MDC key","MDC value");
```

```json:ログ抜粋
"MDC key": "MDC value"
```

* `log.info（）`の第一引数に渡した内容は`<message>`タグの位置に出力される

```（抜粋）TestController.java
log.info("JSON Log",v("arg key","arg value"));
```

```json:ログ抜粋
"message": "JSON Log"
```

* `log.info（）`の第二引数以降に`StructuredArguments.v(key,value)`を渡すと、`<arguments>`タグの位置にその内容が出力される

```（抜粋）TestController.java
log.info("JSON Log",v("arg key","arg value"));
```

```json:ログ抜粋
"arg key": "arg value"
```