検証したミドルウェアのバージョン
$ nginx -v
nginx version: nginx/1.14.0
$ td-agent --version
td-agent 0.12.40
Nginxのconf
アクセスログの形式
HTTPのHostヘッダはNginxのログでserver_name:$server_name\t
で記録するように設定する。
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main
'time:$time_local\t'
'server_name:$server_name\t'
'remote_addr:$remote_addr\t'
'x_forwarded_for:$http_x_forwarded_for\t'
'request_method:$request_method\t'
'request_uri:$request_uri\t'
'status:$status\t'
'size:$body_bytes_sent\t'
'referer:$http_referer\t'
'agent:$http_user_agent\t'
'request_time:$request_time\t'
'upstream_response_time:$upstream_response_time'
;
access_log /var/log/nginx/access.log main;
Nginxのアクセスログをsyslogに送る
FluentdでS3にアクセスログを飛ばすために、Nginxのaccess_log
でファイルパスを指定するのではなく、syslogを指定する。(ファイルをFluentdのin_tail
プラグインによってS3にとばすこともできるが、syslog経由にすればNginxのアクセスログのlogrotateを気にする必要がなくなる。Nginxに大量にアクセスがある場合、アクセスログの肥大化とlogrotateの頻度など考えなければならないことが増えてしまう。)
S3に送りたいのは大本のアクセスログではなく、実際にサービスを提供するエンドポイントになるVirtualHostのアクセスログなので、VirtualHostのaccess_log
をsyslogで設定する。
server {
listen 80;
server_name api1.example.com;
access_log syslog:server=localhost:5140,facility=local7,tag=nginx,severity=info main;
syslogにアクセスログを送るには、NGINX DocumentationのLogging to Syslogを参照。
The facility= parameter specifies the type of program that is logging the message. The default value is local7. Other possible values are: auth, authpriv, daemon, cron, ftp, lpr, kern, mail, news, syslog, user, uucp, local0 ... local7.
The tag= parameter applies a custom tag to syslog messages (nginx in our example).
The severity= parameter sets the severity level of syslog messages for access log. Possible values in order of increasing severity are: debug, info, notice, warn, error (default), crit, alert, and emerg. Messages are logged at the specified level and all more severe levels. In our example, the severity level error also enables crit, alert, and emerg levels to be logged.
syslogをFluentdがうけてS3にとばす
S3の固定のパスへログを送信する
/etc/td-agent/td-agent.conf
では<source>
でsyslogをみて、<match>
でS3にとばす。
S3のパス構造として、先頭にFQDNを入れたいと考えると、path
の先頭にapi1.example.com
のように記載する必要がある。しかし固定文字列をいれてしまうと、VirtualHostの数だけこの設定を用意しなくてはいけない。
<source>
@type syslog
port 5140
bind 127.0.0.1
tag syslog
</source>
<match syslog.local7.info>
@type s3
aws_key_id XXXXXXXXXXXXXXXXXXXX
aws_sec_key XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
s3_bucket nginx_access_log
s3_region ap-northeast-1
format single_value
flush_interval 60
buffer_type file
buffer_path /var/log/td-agent/buffer/access_log.buffer
path "api1.example.com/dt=%Y-%m-%d-%H/#{Socket.gethostname}_"
time_slice_format %Y%m%dT%H
</match>
S3のパスをログに合わせて変える
path
の設定を実際のアクセスログのserver_name
によって変動させられるように、以下のサイトを参考に書き換える。
- 自在にタグを書き換える fluent-plugin-rewrite-tag-filter でログ解析が捗るお話 #fluentd
- Fluentdのタグ書き換えが捗る「tag_parts」プレースホルダを使ってみよう
td-agent-gem install
まずは必要なgemをインストールする。
$ sudo td-agent-gem install fluent-plugin-forest
$ sudo td-agent-gem install fluent-plugin-rewrite-tag-filter
$ td-agent-gem list | grep forest
fluent-plugin-forest (0.3.3)
fluent-plugin-rewrite-tag-filter (1.5.6)
タグを書き換える
Nginxのアクセスログの形式から正規表現でFQDNが抜き出せる。抜き出したFQDNを使って新たにFluentdのtag
を作成する。
<match syslog.**>
@type rewrite_tag_filter
rewriterule1 message server_name:([0-9a-zA-Z_\.\-]+) server_name.$1
</match>
使ったプラグインはrewrite_tag_filter
のrewriterule
。
新しいタグをmatchでひろい、タグに合わせてpathを設定する
新しいタグを<match>
でひろう。
<match server_name.**>
@type forest
subtype s3
<template>
略
buffer_type file
buffer_path /var/log/td-agent/buffer/${tag_parts[1..-1]}.access_log.buffer
path "${tag_parts[1..-1]}/dt=%Y-%m-%d-%H/#{Socket.gethostname}_"
time_slice_format %Y%m%dT%H
</template>
</match>
forest
プラグインを使うことでtag_parts
が使えるようになるので、FQDNを元に作成した新しいタグからFQDN部分をtag_parts
で抜き出し、path
に設定する。
S3のパスをログに合わせて変えるtd-agent.conf
td-agent.conf全文を載せる。
$ cat /etc/td-agent/td-agent.conf
<source>
@type syslog
port 5140
bind 127.0.0.1
tag syslog
</source>
<match syslog.**>
@type rewrite_tag_filter
rewriterule1 message server_name:([0-9a-zA-Z_\.\-]+) server_name.$1
</match>
<match server_name.**>
@type forest
subtype s3
<template>
aws_key_id XXXXXXXXXXXXXXXXXXXX
aws_sec_key XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
s3_bucket nginx_access_log
s3_region ap-northeast-1
format single_value
flush_interval 60
buffer_type file
buffer_path /var/log/td-agent/buffer/${tag_parts[1..-1]}.access_log.buffer
path "${tag_parts[1..-1]}/dt=%Y-%m-%d-%H/#{Socket.gethostname}_"
time_slice_format %Y%m%dT%H
</template>
</match>
ちなみに最近はforest
プラグインはFluentd本体に取り込まれているため、要件によってはプラグインをインストールしなくても書けるらしい。
Fluentd v0.14 では fluent-plugin-forest が不要な話