[PR] あなたが Kindle で読みたいその本、Kindle に対応したら Twitter でお知らせします。

nginx で UUID を生成して X-Request-Id ヘッダを追加する

Posted on

nginx で UUID を生成して X-Request-Id ヘッダを追加する方法を調べてみました。 X-Request-Id ヘッダをレスポンスに含めておけば、Web / App サーバのログをリクエスト毎に串刺し検索できるので、問題が起きたときにスムーズに調査できます。

X-Amzn-Trace-Id は検討したものの…

本題に入る前に。もともとは nginx で UUID を生成するのではなく、ALB が追加する X-Amzn-Trace-Id ヘッダを使おうと思っていました。 X-Amzn-Trace-IdField=version-time-id というフォーマットになっています。

X-Amzn-Trace-Id: Self=1-67891234-12456789abcdef012345678;Root=1-67891233-abcdef012345678912345678

ALB が自動的に付与してくれるので UUID 生成のコストがかかりませんが、Rails の ActionDispatch::RequestId は "max of 255 chars and alphanumeric and dashes only" という制約があり、そのままでは使えないことがわかりました。

ngx_txid で UUID を生成する

さて、ここからが本題です。 X-Request-Id の値となる UUID を生成するために ngx_txid を使います。このモジュールを使うと $txid という nginx の変数で UUID が取得できます。

ngx_txid is a module that exposes $txid: a cached, request scoped, 20 character, base32hex encoded, temporally and lexically sortable, case insensitive, 96 bit identifier.

ngx_txid を使うには nginx のコンパイル時に --add-module で指定する必要があります。

--add-module=path/to/ngx_txid

nginx -V でコンパイルオプションが確認できます。ワンライナーで確認するなら、こんな感じです。

nginx -V 2>&1 | tr " " "\n" | grep ngx_txid
--add-module=/usr/local/src/ngx_txid

問題なければ、あとは $txid を HTTP ヘッダやログに設定するだけです。ログは log_format に追加するだけですが、HTTP ヘッダはアプリケーションサーバによって設定が違います。

nginx + Rack の場合

nginx + Unicorn のように Rack サーバへリバースプロキシする場合は proxy_set_header でプロキシサーバに渡します。

server {
    listen      80;
    server_name example.com;

    location / {
        remove_header    X-Request-Id;
        add_header       X-Request-Id $txid;
        proxy_set_header X-Request-Id $txid;
        proxy_pass       http://localhost:8080;
    }
}

nginx + Passenger の場合

nginx + Passenger の場合はリバースプロキシするわけではないので proxy_set_header は当然効きません。 Passenger の場合は passenger_set_header を使います。

server {
    listen      80;
    server_name example.com;

    location / {
        remove_header        X-Request-Id;
        add_header           X-Request-Id $txid;
        passenger_enabled    on;
        passenger_set_header X-Request-Id $txid;
    }
}

まとめ

ngx_txid を使えば、nginx で UUID を生成して X-Request-Id ヘッダが追加できました。本番環境にも導入しましたが UUID 生成の CPU 負荷も気になりません。

本来は上流にあるロードバランサで追加するのが理想的なので、引き続き ALB の X-Amzn-Trace-Id ヘッダを使う方法を考えてみようと思います。