Liberty で標準出力に JSON をラッピングなしで出力できるようになった

Open Liberty の 下記 blog に、「JSON を System.out にラッピングなしで出力できるようになった」とあるが、説明が今一つ分かりにくい(？)ので、検証ついでに投稿します。

- [Customize HTTP access log fields in JSON logs and write JSON directly to system.out without wrapping on Open Liberty 20.0.0.8](https://openliberty.io/blog/2020/07/30/json-logging-open-liberty-20008.html)

## 今までは、JSON 形式で出力できなかったのか？
Liberty の標準出力(console.log)の形式は、環境変数、bootstrap.properties、server.xml の何れかで JSON 形式に変更できました。

* 環境変数： `WLP_LOGGING_CONSOLE_FORMAT=JSON`
* bootstrap.properties: `com.ibm.ws.logging.console.format=JSON`
* server.xml: `<logging consoleFormat="JSON"/>`

しかし、この状態でアプリケーションが System.out に JSON 形式のメッセージを出力しても、残念ながら、メッセージが文字列としてラッピングされて出力されていました。

例えば、アプリケーションが以下のメッセージを出力すると、

```
{"level" : "WARN",
 "message" : "連携先システムの応答が悪化しています。"}
```

標準出力(console.log)には、以下の様にラッピングされて出力されていました。

```
{"type":"liberty_message","host":"9.85.48.106","ibm_userDir":"C:\/opt\/wlp\/usr\/","ibm_serverName":"open-liberty","message":"{\"level\" : \"WARN\",\n \"message\" : \"連携先システムの応答が悪化しています。\"}","ibm_threadId":"0000002e","ibm_datetime":"2020-09-01T09:01:12.162+0900","module":"SystemOut","loglevel":"SystemOut","ibm_methodName":"","ibm_className":"","ibm_sequence":"1598918472162_0000000000048","ext_thread":"Default Executor-thread-1"}
```

分かりにくいので、jq で整形すると以下の様になります。

```
{
  "type": "liberty_message",
  "host": "9.85.48.106",
  "ibm_userDir": "C:/opt/wlp/usr/",
  "ibm_serverName": "open-liberty",
  "message": "{\"level\" : \"WARN\",\n \"message\" : \"連携先システムの応答が悪化しています。\"}",
  "ibm_threadId": "0000002e",
  "ibm_datetime": "2020-09-01T09:01:12.162+0900",
  "module": "SystemOut",
  "loglevel": "SystemOut",
  "ibm_methodName": "",
  "ibm_className": "",
  "ibm_sequence": "1598918472162_0000000000048",
  "ext_thread": "Default Executor-thread-1"
}
```

アプリケーションが出力した JSON データが、Liberty のログ出力の message 要素としてラッピングされて出力されています。これを、JSON として処理するには、ひと手間必要になってしまいます。

## JSON 形式での直接出力を試してみる
Open Liberty 20.0.0.8 で追加された機能を試してみます。bootstrap.properties または server.xml に以下の指定を追加すると、この機能が有効になります。

* bootstrap.properties: `com.ibm.ws.logging.apps.write.json=true`
* server.xml: `<logging appsWriteJson="true"/>`

先ほどと同じメッセージをアプリケーションが出力すると、アプリケーションが出力したそのままの形式で、 標準出力  (console.log) に出力されます。
Liberty が出力するメッセージの message 要素として出力されるわけではなく、本当にそのまま出力されます。

```
{"level" : "WARN",
 "message" : "連携先システムの応答が悪化しています。"}
```

少し脱線しますが、出力メッセージが "{" で始まっていると、JSON 形式のデータとして判断され、そのまま標準出力  (console.log) に出力され、それ以外の時は従来と同じ扱いのようです。


## 不要な要素を Liberty の JSON 形式の標準出力(console.log)から除去する
ついでに、JSON 形式の標準出力(console.log)から不要な要素を除去する方法を試してみました。こちらは、Open Liberty 20.0.0.5 で追加された機能です。

- [Updates to EJB persistent timers coordination and failover across servers is now available on Open Liberty 20.0.0.5 | Omit specified fields from JSON logging output](https://openliberty.io/blog/2020/05/07/EJB-persistent-timers-20005.html)

JSON 形式の標準出力(console.log)には、あまり役に立ちそうにない要素が入っています。上記の出力例でも確認できますが、例えば、以下のような要素です。特に、Liberty をコンテナとして稼働させている場合は、全てのコンテナから同じ情報が出力されることになるので、まったく意味がない情報となります。

* ibm_userDir
* ibm_serverName

このような不要な要素は、bootstrap.properties に以下のような指定を追加すると出力を抑止できます。

* bootstrap.properties: `com.ibm.ws.logging.json.field.mappings=message:ibm_userDir:,ibm_serverName:`

## 終わりに
内容としては、冒頭で紹介した blog の内容の確認だけなのですが、いかがでしたでしょうか。

Liberty をコンテナ環境で稼働させる場合、アプリケーションのログを JSON 形式で System.out (コンテナの標準出力) に書き出し、Logstash や fluentd で JSON としてパースして Elasticsearch に JSON 形式で転送したくなります。今回の機能は、このような時にぴったりの機能です。


なぜ、今まで、できなかったんでしょうか？？？