Lubuntu 16.04 で fluentd ( td-agent ) を利用する 2 – nginx のアクセスログをパース

概要

fluentd のインストールと単体動作確認は前回終わらせましたので、今回は nginx のアクセスログをパースしていきたいと思います。

手順

監視対象ログのパーミッション設定を変更する

td-agent は、td-agent ユーザとして実行されています。


$ ps aux | grep td-
td-agent  1639  0.0  0.3 122772 31844 ?        Sl   10月21   0:00 /opt/td-agent/embedded/bin/ruby /usr/sbin/td-agent --log /var/log/td-agent/td-agent.log --daemon /var/run/td-agent/td-agent.pid
td-agent  1644  0.0  0.8 168340 66112 ?        Sl   10月21   3:19 /opt/td-agent/embedded/bin/ruby /usr/sbin/td-agent --log /var/log/td-agent/td-agent.log --daemon /var/run/td-agent/td-agent.pid

そのため、td-agent ユーザがログファイルの読み取りができるようにパーミッションを変更します。


$ sudo chmod 644 /var/log/nginx/*

logrotate された際のパーミッション設定も変更しておきます。


$ sudo vi /etc/logrotate.d/nginx
/var/log/nginx/*.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 0644 www-data adm
        sharedscripts
        prerotate
                if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
                        run-parts /etc/logrotate.d/httpd-prerotate; \
                fi \
        endscript
        postrotate
                invoke-rc.d nginx rotate >/dev/null 2>&1
        endscript
}

fluentd の設定追加

fluentd ( td-agent ) の設定をします。問題となるのは、format として指定する正規表現くらいでしょう。これは監視対象となるログの文字列によって変わってくるため、その都度正規表現を書くのが面倒ですなぁ。これは如何ともし難いものであるか。と思ったらすでに実践されている方がいらっしゃいました。fluentular を利用すると良さそう!なのだが、部分的にはうまくいくのだけど、正しくても結果表示がされなかったり、Internal Server Error が返されたりする感じ。特定の文字列から正規表現を提案してくれるようなウェブサービスがあったら便利だなぁつくれたらつくりたいな。。パッと思い浮かぶのは形態要素解析なのですが、解体要素っつてもこれは名詞、これは動詞のような語彙の情報が前提にある。しかし、ログは違うからパターンマッチの「種」として人間が補助するのはデリミタくらいにしてそこから斬りさばいていくような方式なら実装できるかなぁ、いや無理かなぁなどと考える。

format 以外の注意点として、<source> タグ中の tag で指定した名前(この例では nginx.access )と <match> タグでの指定は同一にする(この例では <match nginx.access> )必要がある。


$ sudo vi /etc/td-agent/td-agent.conf
# nginx access.log
<source>
  type tail
  tag nginx.access
  path /var/log/nginx/access.log
  pos_file /var/log/td-agent/nginx-access.log.pos
  format /^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)" "(?<forwarder>[^\"]*)")?/
  time_format %d/%b/%Y:%H:%M:%S %z
</source>

<match nginx.access>
  type file
  path /tmp/test
</match>

動作確認

td-agent を再起動し、nginx にアクセスがあると以下のような感じでアクセスログがパースされて JSON 形式で必要な key / value が確認できていれば問題ありません。このとき、/tmp/test にログが出力されるのではなく、/tmp/test.timestamp.hash のような名前のファイルに出力されます。<match> タグで暗黙に buffer_path /tmp/test.* と定義されているようです。


$ sudo tail -f /tmp/test.20161027.b53fd26283b59abc3
2016-10-27T14:55:37+09:00       nginx.access    {"remote":"111.222.333.444","host":"-","user":"-","method":"GET","path":"/wp-content/plugins/jetpack/_inc/jquery.jetpack-resize.js","code":"304","size":"95"}
2016-10-27T14:55:37+09:00       nginx.access    {"remote":"111.222.333.444","host":"-","user":"-","method":"GET","path":"/wp-content/plugins/jetpack/_inc/jquery.inview.js","code":"304","size":"95"}
2016-10-27T14:55:37+09:00       nginx.access    {"remote":"111.222.333.444","host":"-","user":"-","method":"GET","path":"/wp-content/plugins/jetpack/modules/likes/queuehandler.js","code":"304","size":"95"}
2016-10-27T14:55:37+09:00       nginx.access    {"remote":"111.222.333.444","host":"-","user":"-","method":"GET","path":"/wp-content/plugins/jetpack/modules/sharedaddy/sharing.js","code":"304","size":"95"}
2016-10-27T14:55:38+09:00       nginx.access    {"remote":"111.222.333.444","host":"-","user":"-","method":"GET","path":"/wp-content/uploads/2016/10/newrsynclogo.jpg","code":"304","size":"0"}
2016-10-27T14:55:46+09:00       nginx.access    {"remote":"111.222.333.444","host":"-","user":"-","method":"GET","path":"/security/ssl-certificate/3050/?relatedposts=1","code":"200","size":"2239"}

トラブルシューティング

正規表現のミス

format で正規表現のミスがあると以下のようにサービスが再起動できず、syslog にエラーが記録されます。


$ sudo /etc/init.d/td-agent restart
[....] Restarting td-agent (via systemctl): td-agent.serviceJob for td-agent.service failed because the control process exited with error code. See "systemctl status td-agent.service" and "journalctl -xe" for details.
 failed!

syslog に出力されるエラーの例


Oct 27 00:11:54 vm-nfj-201 td-agent[21782]: Starting td-agent: 2016-10-27 00:11:54 +0900 [error]: fluent/supervisor.rb:373:rescue in main_process: config error file="/etc/td-agent/td-agent.conf" error="Invalid regexp '^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \\[?<time>[^\\]]*)\\] \"(?<method>\\S+)(?: +(?<path>[^ ]*) +\\S*)?\" (?<code>[^ ]*) (?<size>[^ ]*)(?: \"(?<referer>[^\\\"]*)\" \"(?<agent>[^\\\"]*)\" \"(?<forwarder>[^\\\"]*)\")?': unmatched close parenthesis: /^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \\[?<time>[^\\]]*)\\] \"(?<method>\\S+)(?: +(?<path>[^ ]*) +\\S*)?\" (?<code>[^ ]*) (?<size>[^ ]*)(?: \"(?<referer>[^\\\"]*)\" \"(?<agent>[^\\\"]*)\" \"(?<forwarder>[^\\\"]*)\")?/"

ログが出力されない

td-agent.log を確認すると permisson error が出ている場合は監視対象ログのパーミッションを見直します。644 であれば、少なくとも td-agent に読み取り権限があるはず。


$ sudo less /var/log/td-agent/td-agent.log
2016-10-27 00:32:51 +0900 [error]: Permission denied @ rb_file_s_stat - /var/log/nginx/access.log
  2016-10-27 00:32:51 +0900 [error]: suppressed same stacktrace

td-agent ユーザでのチェック

Lubuntu 16.04 では、fluentd をインストールすると td-agent というユーザが作られる。設定は正しい筈だが、/var/log/td-agent/td-agent.log や /var/log/syslog の出力を見ても原因がわからない場合に sudo で td-agent ユーザになると切り分けがつくことがあった。一旦、td-agent を停止してから sudo で td-agent になってみると以下のような出力がでてリアルタイムに待ち受け状態となる。つまり、td-agent 自身がどのように起動しているかや受信している情報を目視確認できるので意外と使える方法ではなかろうか。抜けるときは、Ctrl+C で終了できます。


$ /etc/init.d/td-agent stop
$ sudo td-agent
2016-10-27 14:58:08 +0900 [info]: reading config file path="/etc/td-agent/td-agent.conf"
2016-10-27 14:58:08 +0900 [info]: starting fluentd-0.12.29
2016-10-27 14:58:08 +0900 [info]: gem 'fluent-mixin-config-placeholders' version '0.4.0'
2016-10-27 14:58:08 +0900 [info]: gem 'fluent-mixin-plaintextformatter' version '0.2.6'
2016-10-27 14:58:08 +0900 [info]: gem 'fluent-plugin-kafka' version '0.3.1'
2016-10-27 14:58:08 +0900 [info]: gem 'fluent-plugin-mongo' version '0.7.15'
2016-10-27 14:58:08 +0900 [info]: gem 'fluent-plugin-rewrite-tag-filter' version '1.5.5'
2016-10-27 14:58:08 +0900 [info]: gem 'fluent-plugin-s3' version '0.7.1'
2016-10-27 14:58:08 +0900 [info]: gem 'fluent-plugin-scribe' version '0.10.14'
2016-10-27 14:58:08 +0900 [info]: gem 'fluent-plugin-td' version '0.10.29'
2016-10-27 14:58:08 +0900 [info]: gem 'fluent-plugin-td-monitoring' version '0.2.2'
2016-10-27 14:58:08 +0900 [info]: gem 'fluent-plugin-webhdfs' version '0.4.2'
2016-10-27 14:58:08 +0900 [info]: gem 'fluentd' version '0.12.29'
2016-10-27 14:58:08 +0900 [info]: adding match pattern="td.*.*" type="tdlog"
2016-10-27 14:58:09 +0900 [info]: adding match pattern="debug.**" type="stdout"
2016-10-27 14:58:09 +0900 [info]: adding match pattern="nginx.access" type="file"
2016-10-27 14:58:09 +0900 [info]: adding source type="forward"
2016-10-27 14:58:09 +0900 [info]: adding source type="http"
2016-10-27 14:58:09 +0900 [info]: adding source type="debug_agent"
2016-10-27 14:58:09 +0900 [info]: adding source type="tail"
2016-10-27 14:58:09 +0900 [info]: using configuration file: <ROOT>
  <match td.*.*>
    @type tdlog
    apikey xxxxxx
    auto_create_table 
    buffer_type file
    buffer_path /var/log/td-agent/buffer/td
    buffer_chunk_limit 33554432
    <secondary>
      @type file
      path /var/log/td-agent/failed_records
      buffer_path /var/log/td-agent/failed_records.*
    </secondary>
  </match>
  <match debug.**>
    @type stdout
  </match>
  <source>
    @type forward
  </source>
  <source>
    @type http
    port 8888
  </source>
  <source>
    @type debug_agent
    bind 127.0.0.1
    port 24230
  </source>
  <source>
    type tail
    tag nginx.access
    path /var/log/nginx/access.log
    pos_file /var/log/td-agent/nginx-access.log.pos
    format /^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)" "(?<forwarder>[^\"]*)")?/
    time_format %d/%b/%Y:%H:%M:%S %z
  </source>
  <match nginx.access>
    type file
    path /tmp/test
    buffer_path /tmp/test.*
  </match>
</ROOT>
2016-10-27 14:58:09 +0900 [info]: listening fluent socket on 0.0.0.0:24224
2016-10-27 14:58:09 +0900 [info]: listening dRuby uri="druby://127.0.0.1:24230" object="Engine"
2016-10-27 14:58:09 +0900 [info]: following tail of /var/log/nginx/access.log

参考サイト

Thanks.

スポンサーリンク