検証したミドルウェアのバージョン

$ 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によって変動させられるように、以下のサイトを参考に書き換える。

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_filterrewriterule

新しいタグを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 が不要な話

FluentdとS3の他の記事