nginx

NginxのアクセスログをJSON形式で出力する

TL;DR

log_format ディレクティブでパラメータ escape=json を指定する。

nginx.conf
http {
  :
  log_format json escape=json '{"time": "$time_iso8601",'
    '"host": "$remote_addr",'
    '"vhost": "$host",'
    '"user": "$remote_user",'
    '"status": "$status",'
    '"protocol": "$server_protocol",'
    '"method": "$request_method",'
    '"path": "$request_uri",'
    '"req": "$request",'
    '"size": "$body_bytes_sent",'
    '"reqtime": "$request_time",'
    '"apptime": "$upstream_response_time",'
    '"ua": "$http_user_agent",'
    '"forwardedfor": "$http_x_forwarded_for",'
    '"forwardedproto": "$http_x_forwarded_proto",'
    '"referrer": "$http_referer"}';

  server {
    :
    access_log /path/to/access_log json; # 上で設定したjsonフォーマットを使う
    :
  }
  :
}

解説

この escape パラメータのデフォルト値は default である。
この場合、 " (0x22)や ' (0x27)はそれぞれ \x22, \x27 のようにエスケープされる。1

json オプションはNginx 1.11.8で導入された。

また、Nginx 1.13.10では escape=none によって、エスケープしないというオプションが追加されるようだ。2

数値を数値型で扱わないのはなぜか?

$status$request_time のような、本来JSONの数値型で扱うべき値も "$status" のように文字列型で扱っていることが気になるという人がいるかもしれない。

これらのような値をクォートしない形式で設定するとどうなるだろうか。
実は、値が取得できないときに空文字になり、invalidなJSONになってしまう。
結果として、エラーによりログ出力ができなくなってしまう。

そこで、ここでは簡単のため文字列型で扱う例を示した。

参考

脚注


  1. 0x00-0x1F, 0x7F-0xFFの範囲の文字も同様にエスケープされる。参考: http://nginx.org/en/CHANGES v0.7.0, v1.1.6の変更。 

  2. https://trac.nginx.org/nginx/ticket/1450 のパッチによるようだ。