やりたいこと
nginx のログの書式設定には、log_format
ディレクティブを使いますします。
その中には Variable が使用できて、ここ に書いてあるような変数を埋め込めます。
で、その変数のうち、以下のようなものはリクエストによっては値が無い可能性があります。
- httpヘッダー由来のもの
$http_name
- cookie の値を取り出すやつ
$cookie_name
- httpクエリパラメータを取り出すやつ
$arg_name
これらをそのまま log_format で指定すると、値が存在しないときは値の代わりに -
ダッシュを出力してしまいます。
この挙動を変えたい。具体的には空白を出したい。
やり方
map ディレクティブ を使う
map a $lang { default $http_accept_language; }
map a $argp { default $arg_p; }
log_format dummy 'lang:$lang\tp:$argp'
とかすると、HTTP ヘッダに Accept-Language
が無いときは空白を出してくれます。query に p が与えられなかったら、空白が出ます。
そうなる理由
map の説明を見るとわかるのですが、map string $lang {}
は、string(上の例の場合は固定の a
という文字列) から $lang
という新たな変数を作るのだけど、その際に {}
内の処理をする、という動きをするようです。
で、そこに default $baz
と書いておくと、string にかかわらず、$baz の値を使うようになる。値が無いので、空白文字列が入ると。
値が無いときに -
を入れるのは、ロギング時の仕様で、変数の値を評価するときの仕様というわけでは無さそうです。
この、変数を評価する仕組みが場所によって異なる(というか、log_format の指定が他と異なる?)のを利用して、例えば通常は使えない -
を名前に含むような cookie の値を出力するときの hack などにも使われるようです(というか、そこから inspire した)。
発展。値が無いときに任意の文字を使う
ログに変数の値が存在しないとき、-
ではなく空白を出すことはできましたが、「任意の文字列」を出せるようにしてみましょう。
map $http_x_forwarded_for $xff {
default $http_x_forwarded_for;
"" "=";
}
こうです。
$http_x_forwarded_for
から $xff
を作りますが、""
(空文字列)と一致したときは =
を使い、一致しなかったとき(つまり、値があるときですね)は $http_x_forwarded_for
の値を使う、という意味です。
任意の文字に変えるのはあんまりニーズ無さそうですが、なんか応用ができるかもしれません。
他の方法を知りたい
もっとスマートな方法は無いのですかね...