access_logからエラー解析したい [nginx]

Pocket

目的

ユーザーのエラー状況をエラーログから追えるようにnginxでログを収集できるように設定を行います

前提条件

nginxインストール済みでウェルカムページが閲覧できるところまでは設定が完了している

設定手順

設定ファイルにフォーマットと出力条件式を記載

httpコンテキスト内に判定用のmapとlog_formatを追加しました。

今回は4xxエラーと5xxエラーを分けてログに保存しておきたかったので、条件をそれぞれわけています。

ログはjson形式で出力し、調査に必要な情報(リクエスト文、IPアドレス、URLなど)を取得できるように設定しています。

http {
    map $status $res_status_4xx {
        #レスポンスのステータスコードが4xxの場合、1をセット
        ~^[4] 1;

        default 0;
    }

    map $status $res_status_5xx {
        #レスポンスのステータスコードが5xxの場合、1をセット
        ~^[5] 1;

        default 0;
    }

    log_format error_res  escape=json '{"time":"$time_local",'
                                      '"forwarded_for":"$http_x_forwarded_for",'
                                      '"client":"$remote_addr",'
                                      '"status":"$status",'
                                      '"request":"$request",'
                                      '"referer":"$http_referer",'
                                      '"request_body":"$request_body",'
                                      '"body_bytes_sent":$body_bytes_sent,'
                                      '"user_agent":"$http_user_agent",'
                                      '"authorization":"$http_authorization"}';

...

ログ出力先の設定(ログフォーマットと出力条件)

今回は/etc/nginx/nginx.confのserverコンテキスト内に記入していますが、任意の設定ファイル内に記述してください。

すべてのアクセスログ、400エラー、500エラーの合計3つのログが記録されます。

ログフォーマットはエラー時のみ先ほど作成したerror_resのフォーマットを利用しています。

server {
    ....
    access_log   /var/log/nginx/access.log;
    access_log   /var/log/nginx/error4xx.log error_res if=$res_status_4xx;
    access_log   /var/log/nginx/error5xx.log error_res if=$res_status_5xx;
    ....

ログローテート

最後にログローテートの設定もしておきます。

日毎にログファイルを圧縮保存し、過去60日分保存されるようにしています。

/var/log/nginx/*log {
    create 0664 nginx root
    daily
    rotate 60
    missingok
    notifempty
    compress
    sharedscripts
    postrotate
        /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
    endscript
}

nginx再起動

設定が完了したら、nginx -t でフォーマット形式を確認し問題なかったらnginxを再起動してください。

ログ出力の確認

curlコマンド等でリクエストを送ったら、ログファイルに保存されているか確認してみてください。

保存されていたら設定は完了です!

ちなみに私の場合は以下の形式で保存されていました。(500エラーの場合)

{
	"time": "10/Oct/2022:10:51:43 +0000",
	"forwarded_for": "{アクセス元のIPアドレス}",
	"client": "{client_ip}",
	"status": "500",
	"request": "POST {URI} HTTP/1.1",
	"referer": "{URL}",
	"request_body": "{リクエスト文}",
	"body_bytes_sent": 0,
	"user_agent": "{user_agent}",
	"authorization": "{認証トークンが設定されていればここに記入される}"
}

今後やりたいこと

  • ログをS3に転送
  • エラー時にはレスポンス文も含めるようにする