📘

NginxとGETパラメーターで簡単なログ収集システムを作る

2024/01/15に公開

元々、弊プロダクトでアクセスログなどをサーバーサイドから中心にできる分析を行っていました。
この先もっと細かいログを収集する際にクリックログやその他イベントログであったりをが必要ではないかという話になり、このときにクライアントからリクエストを受け取って、分析基盤であるBigQueryにデータを転送する仕組みが必要でした。

すでにBigQueryにデータを転送する仕組み自体はFluentdで作っていたので、一旦クライアントからリクエストした内容を受け取れるバックエンドがあればOKそうなので、ログ収集システムのバックエンドをNginxだけでデモンストレーションとしてログ収集システムを作ってみることにしました。

Nginxにした理由

単にGETリクエストを受け取るだけのサーバーなので、動的な処理は不要で、
そこまで要求されるパフォーマンス要件が高いわけではないのですが、Nginxにしておけば、パフォーマンスについてはスケールアウトする仕組みがあれば保証されているのではないか?
というと、設定がシンプルで済みそうだったのが今回使ってみた理由です。
昔こういった仕組みを作っていたというアドバイスもいただき取り組んでみたというのが理由だったりします。

NginxとGETパラメーターで実現

Webクライアントに対しては成功したことだけをレスポンスすればよいので、204のステータスコードを返せばいいですし、この手のものにはHTTPリクエストはPOSTにして、リクエストパラメーターを読み込むような方法が主流かもしれないですが、
Nginxの設定をシンプルに保つにはGETパラメーターを利用するのが手っ取り早かったので、こちらを利用することにしました。

なぜサーバーレスにしないのか?

要件的にはサーバーレスでも問題がないように感じます。
AWSであればLamdbaであっても同じようなことはできますし、下手すればランニングコストは安いし、デプロイもECSやEC2より簡単になると思います。
しかし、弊プロダクトではまだLambda -> BigQueryへの転送ルートについては簡単にできるようになっていないのが現状だったりします。
AWS -> BigQueryへの転送は基本Fluentdを使っていて、Fluentdの集約サーバーに送信して、そこからBigQueryに転送しているということを行っています。
この集約サーバーを活用にするにはサーバーレスだとちょっと面倒で、Fluentdをそのまま利用できるFargateで実現したかったというのが理由です。

Nginxの設定など

具体的なNginxの設定は下記です。
Nginxの基本的な利用方法を知っていれば下記で済みます。

1. log_formatを変更する

LogFormatを変更してGETパラメーターをアクセスログに含めるようにしてください。
サンプルアプリケーションではLTSVを使っています。これは弊プロダクトのログ送信時のフォーマットがLTSVになっているためです。

log_format main 'time:$time_iso8601\t'
	  'remote_addr:$remote_addr\t'
	  'request_method:$request_method\t'
	  'request_uri:$request_uri\t'
	  'status:$status\t'
	  'body_bytes_sent:$body_bytes_sent\t'
	  'http_referer:$http_referer\t'
	  'http_user_agent:$http_user_agent\t'
	  'query_params:$args';

2. サーバの設定

実際にWebアクセスを受け取るサーバの設定です。
HTTPGETリクエスト「以外」をエラーにするようにして、別のアクセスログに記録するようにしています。これで必要な設定は終了しました。

server {
    listen 80;
    location / {
        client_max_body_size 2M;

        # allow GET requests only
        if ($request_method != GET) {
            access_log /var/log/nginx/not_allowed.log main;
            return 405;
        }

        access_log /var/log/nginx/access.log main;
        return 204;
    }
}

仕上げ

仕上げにアクセスログをNginxのアクセスログからBigQueryに送信するように設定完了すれば完了です。このツール自体にデプロイの仕組みは内包されていないので、適宜Fargateだったりにデプロイをするようにしてください。
ここでは特に言及していないですが、
認証を簡単でもよいのでつけたいということであればBASIC認証をつけると良いと思います。

モチベーションなど

DHHのkamal-skiffに感銘を受けた

SkiffはBasecampのために作ったツールセットです。実態としてはKamalというDockerを簡単にデプロイするための仕組み(Kamal)と、NginxでSSI(Server Side Includes)を有効にしたDockerイメージであるという極めてシンプルなプロダクトです。

https://github.com/basecamp/kamal-skiff

SSI自体は昔から存在している技術で、部分的に注意が必要になる仕組みですが、
ただのHTMLに対してヘッダ=やフッターを共通化することをSSIが動的にファイル生成をするので「ビルド」しなくても可能です。
このskiffを使って37Signalsのコーポレートサイトであったりが運用されていて、便利に活用されているようです。
https://twitter.com/dhh/status/1717673944105570385

上記Xのポストでもあるように、SSI自体は昔からある枯れた技術であり「石器時代のツール」です。
新しい技術ふんだんに使って課題を解決することも良いのですが、DHHのように枯れた技術に対して再度注目し解決していく姿勢に感銘を受け、私も枯れた技術を使って課題解決をしてみたくなりました。

まとめ

Webのイベントログを収集するバックエンドとして、Nginxを採用しWebリクエストのGETパラメーターでアクセスログに保存しておくというシンプルな仕組みを紹介しました。
あくまでもデモンストレーションであり、本番利用するかはわかりませんが、今後様々なクライアントサイドのログを使った分析をしていければと思います。

OSIRO テックブログ

Discussion