eXcale開発チームの泉谷(@syguer)です。
今回はNginxのアクセスログをLTSV形式にする方法と、そのログをfluentdで転送する方法について紹介します。
eXcaleではNginxのアクセスログをflluentdで集約し解析を行っていますが、アクセスログの出力形式をLTSVにしています。LTSV形式にすることで後からログに出力したい項目を変更してもfluentdの設定を変更しなくてよいなどのメリットがあります。
eXcaleでは期間限定でサインアップキャンペーン実施中です。
まだ登録されていない方は、この機会にアプリ公開の手軽さを体験してみてください。
サインアップはこちらから。
キャンペーン内容についてはこちらを参照してください。
LTSVとは
Labeled Tab-separated Valuesの略で、最近注目されだしたフォーマットです。
主にApacheやNginxなどのログで使われることが想定されています。
メリットはパースしやすいことと、値を増やしやすいことです。
LTSVは以下のようなルールで記述されます。
・「label : value」のようにコロンで繋いだラベルと値一組で要素とする
・要素の区切りにタブ文字を使う
詳しい仕様などについては以下のサイトでまとめられているので、そちらを参照してください。
Nginxのログ出力をLTSV形式にする
Nginxのアクセスログはデフォルトではcombined形式で出力されます。
これを設定ファイルにすると以下のようになります。
1 2 3 |
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent"'; |
これをLTSVで書くと以下のようになります。
1 2 3 4 5 6 7 8 |
log_format ltsv "remote_addr:$remote_addr\t" "remote_user:$remote_user\t" "time_local:$time_local\t" "request:$request\t" "status:$status\t" "body_bytes_sent:$body_bytes_sent\t" "http_refer:$http_referer\t" "http_user_agent:$http_user_agent"; |
このようにlabelとvalueをコロンで区切り、要素の最後にタブ文字を指定します。
fluentd側の設定
fluentd側ではNginxのアクセスログをtailプラグインで取得し、formatでltsvを指定します。
以下が設定例です。この例では動作を確認するために、ログの転送先をローカルのファイルとしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# Input <source> type tail path /usr/local/nginx/logs/access.log format ltsv time_key time_local time_format %d/%b/%Y:%H:%M:%S %z pos_file /var/tmp/nginx_access_log.pos tag nginx.access </source> # Output <match nginx.*> type file path /tmp/sample.log </match> |
注意点
fluentdでは取得したデータにタイムスタンプを付与するために時刻のフィールドが必要になります。
ltsvをformatに選択した場合、具体的には以下のどちらかが必要です。
・“time”という名前がlabelになっていて、valueが時刻に変換できる要素
・valueが時刻に変換できて、fluentdの設定でtime_keyにlabelが指定されている要素
上記の例ではfluentdのsourceディレクティブ内で”time_key time_local”とすることで対応しています。
もし、このような要素が存在しない場合はfluentd内部でパースに失敗するため、以下のようなエラーを出力して、処理に失敗します。
1 |
error="Value must be string: " |
また、時刻のフィールドを用意しても、 fluentdの設定でtime_formatが指定されていないと以下のようなエラーを出力し、処理に失敗します。
1 |
error="argument out of range" |
これらのエラーは一見Nginxが出したアクセスログの内容に問題があるように見えるため、原因が時刻だと気づけない可能性があります。
もしこのようなエラーが発生した場合は、timeというラベルの要素があるかどうか、時刻のフォーマットが正しいかなどを確認してみてください。
動作確認
fluentdがログを取得し、転送しているか確認してみましょう。
Nginxとfluentdを起動し、localhostに適当にcurlコマンドを叩いてみます。うまくいっていれば出力先として指定したファイルに以下のような出力がされているはずです。
1 |
2014-03-18T00:00:00+00:00 nginx.access {"remote_addr":"127.0.0.1","remote_user":"-","request":"GET / HTTP/1.1","status":"200","body_bytes_sent":"612","http_refer":"-","http_user_agent":"curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.13.6.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2"} |
試しにNginxの設定ファイルを編集し、ログに出力する項目を 足したり消したりしてみてください。
fluentd側はなにもしなくても勝手に対応してくれることがわかると思います。
ここまで動作確認できれば、後はmatchディレクティブを適当な設定に書き換えることでログを転送できます。
ログの転送についてはこちらの記事を参照してください。
最後に
今回はNginxのログフォーマットをLTSV形式に変更する方法と、それをfluentdで受け取る方法を解説しました。
LTSVはその手軽さから様々なプログラミング言語やフレームワークで対応されています。
便利なフォーマットなのでぜひ使ってみてください。