slf4j経由のlog4j2でJSONログを出力する方法

log4j2でJSONログを出力する方法

以下の手順が必要

  • org.apache.logging.log4j:log4j-layout-template-json をクラスパスに入れる
  • log4j2.xmlでJsonTemplateLayoutを設定する

詳しい話はドキュメントに書いてあるが、デフォルトでtemplateを持っているようなので、そちらを使うことも可能なようだ。

https://logging.apache.org/log4j/2.x/manual/json-template-layout.html

log4j2で特定のログでのみフィールドを生やす方法

JSONのテンプレートを変更することなく、JSONログのフィールドを増やしたい場合、slf4j経由で行う場合、以下の2つのアプローチが考えられる。

  • org.slf4j.MDC経由で追加する
  • slf4jのfluent API経由で追加する

これらのアプローチを使えば、特定のログでのみフィールドを生やすことができる。

しかし、フィールドとして以下のようなネストしたオブジェクトを設定したい場合は注意が必要である。

{
  "some": { // someを特定のログでだけ生やしたい
    "object": { "key": "value" }
  }
}

前者のMDCの場合は、API的に MDC#put(String, String) になるので、Object型は渡せないので、HashMapのようなネストしたオブジェクトを渡せない。 後者のfluent APIの場合は、LoggingEventBuilder#addKeyValue(String, Object) になるので、ネストしたオブジェクトを渡せそうに見える。

が、log4j2の実装では、以下の箇所でString.valueOf(value)といったように、Stringに変換しているため、生やすことができるフィールドはStringのみのようだ。

https://github.com/apache/logging-log4j2/blob/2.x/log4j-slf4j2-impl/src/main/java/org/apache/logging/slf4j/Log4jEventBuilder.java#L82

log4j2のAPIも一応見たが、org.apache.logging.log4j.CloseableThreadContextorg.apache.logging.log4j.ThreadContextAPIは keyもvalueもStringを要求するインターフェースになっており ネストしたオブジェクトを渡せない。 渡せる方法があったら教えてほしい・・・。

logstash-logback-encoder のように、logger.info("message", entries(map)); みたいなAPIがあると嬉しかったのだが・・・。 log4j2のLayoutをカスタマイズすれば、ネストしたオブジェクトも生やせるとは思うが そこまでするなら、logbacklogstash-logback-encoder を使えば良さそうである。