CLOVER🍀

That was when it all began.

Fluentdで、Apacheのアクセスログを読み込んで、内容によって出力先(output)を振り分けることを考える

これは、なにをしたくて書いたもの?

Fluentdを使って、ひとつのinputから条件に応じてoutputを振り分ける練習に、と。

お題

Fluentdを使って、Apacheアクセスログをtailして読み込み、HTMLとそれ以外にアクセスした際のログを、別々のoutputに
振り分けるというお題で試してみます。

HTMLに対するアクセスログはElasticsearch、それ以外に対するアクセスログは標準出力(Fluentdのログ)に出力するものとします。

環境

Ubuntu Linux 18.04 LTS上で行い、Fluentdのバージョンは以下とします。

2019-03-09 06:05:25 +0000 [info]: starting fluentd-1.3.3 pid=25 ruby="2.4.5"

Apacheは、同じ環境上でインストール。Apacheで公開するコンテンツは、Apache自身のドキュメントとしましょう。

$ sudo apt install apache2 -y
$ sudo systemctl start apache2.service
$ cd /var/www/html/
$ sudo wget https://www-us.apache.org/dist//httpd/docs/httpd-docs-2.4.33.en.zip
$ sudo unzip httpd-docs-2.4.33.en.zip
$ sudo mv httpd-docs-2.4.33.en/* ./.

Apacheのバージョン。

[Sat Mar 09 06:07:01.535225 2019] [mpm_event:notice] [pid 554:tid 140371125488576] AH00489: Apache/2.4.29 (Ubuntu) configured -- resuming normal operations

Fluentdがアクセスログを読むことができるように、Apacheのログ出力まわりの権限を変更しておきます。

$ sudo chmod 755 /var/log/apache2
$ sudo chmod 544 /var/log/apache2/*

Elasticsearchは、6.6.1で別ホスト(172.17.0.3)で用意。

ここまでが、前提環境です。

Fluentdの設定をする

では、Fluentdの設定をしましょう。

Input Pluginとしてtail、ログのパースにはapache2を使いましょう。

tail Input Plugin | Fluentd

apache2 Parser Plugin | Fluentd

Output Pluginとしては、elasticsearchとstdout。

Elasticsearch Output Plugin | Fluentd

stdout Output Plugin | Fluentd

ログの振り分けには、rewrite_tag_filterでタグを付け替えることで行います。

rewrite_tag_filter Output Plugin | Fluentd

結果、こんな感じになりました。
/etc/td-agent/td-agent.conf

<source>
  @type tail
  @id input_tail
  <parse>
    @type apache2
  </parse>
  path /var/log/apache2/access.log
  pos_file /var/log/td-agent/apache2-access.log.pos
  tag apache.access
</source>

<match apache.access>
  @type rewrite_tag_filter
  @id rewrite_tag
  <rule>
    key path
    pattern /(\/|\.html)$/
    tag apache.access.html
  </rule>
  <rule>
    key path
    pattern /.+/
    tag apache.access.styles
  </rule>
</match>

<match apache.access.html>
  @type elasticsearch
  @id output_elasticsearch
  host 172.17.0.3
  port 9200
  index_name html-access-log
</match>

<match apache.access.styles>
  @type stdout
  @id output_styles_stdout
</match>

ポイントはout_rewrite_tag_filterの設定で、あるキー(項目)に対して正規表現を書いて、マッチしたものに対してタグを
付け替えるように指定します。

<match apache.access>
  @type rewrite_tag_filter
  @id rewrite_tag
  <rule>
    key path
    pattern /(\/|\.html)$/
    tag apache.access.html
  </rule>
  <rule>
    key path
    pattern /.+/
    tag apache.access.styles
  </rule>
</match>

今回は「path」が「/」で終わるか拡張子「.html」だった場合は「tag apache.access.html」というタグにリライトし、

  <rule>
    key path
    pattern /(\/|\.html)$/
    tag apache.access.html
  </rule>

それ以外のものは「apache.access.styles」というタグにリライトしました。

  <rule>
    key path
    pattern /.+/
    tag apache.access.styles
  </rule>

このタグがルーティングされるように、Output Pluginの設定を行っています。

<match apache.access.html>
  @type elasticsearch
  @id output_elasticsearch
  host 172.17.0.3
  port 9200
  index_name html-access-log
</match>

<match apache.access.styles>
  @type stdout
  @id output_styles_stdout
</match>

他のサンプルとしては、out_rewrite_tag_filterのドキュメントにも載っているのでこちらを見てみるとよいでしょう。

Configuration example

ここまで設定したら、Fluentdを再起動。

確認

では、Apacheにアクセスして確認してみます。

f:id:Kazuhira:20190309152606p:plain

Fluentdのログには、以下のように画像やCSSなどに関するアクセスログが出力されます。

2019-03-09 06:24:59.000000000 +0000 apache.access.styles: {"host":"172.17.0.1","user":null,"method":"GET","path":"/style/css/manual-zip.css","code":200,"size":862,"referer":"http://172.17.0.2/","agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}
2019-03-09 06:24:59.000000000 +0000 apache.access.styles: {"host":"172.17.0.1","user":null,"method":"GET","path":"/style/css/prettify.css","code":200,"size":1443,"referer":"http://172.17.0.2/","agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}
2019-03-09 06:24:59.000000000 +0000 apache.access.styles: {"host":"172.17.0.1","user":null,"method":"GET","path":"/images/left.gif","code":200,"size":342,"referer":"http://172.17.0.2/","agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}
2019-03-09 06:24:59.000000000 +0000 apache.access.styles: {"host":"172.17.0.1","user":null,"method":"GET","path":"/style/scripts/prettify.min.js","code":200,"size":13428,"referer":"http://172.17.0.2/","agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}
2019-03-09 06:24:59.000000000 +0000 apache.access.styles: {"host":"172.17.0.1","user":null,"method":"GET","path":"/style/css/manual.css","code":200,"size":4557,"referer":"http://172.17.0.2/","agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}
2019-03-09 06:24:59.000000000 +0000 apache.access.styles: {"host":"172.17.0.1","user":null,"method":"GET","path":"/images/feather.png","code":200,"size":21432,"referer":"http://172.17.0.2/","agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}
2019-03-09 06:24:59.000000000 +0000 apache.access.styles: {"host":"172.17.0.1","user":null,"method":"GET","path":"/style/css/manual-zip-100pc.css","code":200,"size":870,"referer":"http://172.17.0.2/","agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}
2019-03-09 06:24:59.000000000 +0000 apache.access.styles: {"host":"172.17.0.1","user":null,"method":"GET","path":"/style/css/manual-print.css","code":200,"size":3427,"referer":"http://172.17.0.2/","agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}
2019-03-09 06:24:59.000000000 +0000 apache.access.styles: {"host":"172.17.0.1","user":null,"method":"GET","path":"/style/css/manual-loose-100pc.css","code":200,"size":1445,"referer":"http://172.17.0.2/","agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}
2019-03-09 06:24:59.000000000 +0000 apache.access.styles: {"host":"172.17.0.1","user":null,"method":"GET","path":"/favicon.ico","code":404,"size":501,"referer":"http://172.17.0.2/","agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}

一方で、Elasticsearch側には

$ curl '172.17.0.3:9200/html-access-log/_search?q=*&pretty'
{
  "took" : 82,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "html-access-log",
        "_type" : "fluentd",
        "_id" : "OHogYWkBIj4IrKe-DMlO",
        "_score" : 1.0,
        "_source" : {
          "host" : "172.17.0.1",
          "user" : null,
          "method" : "GET",
          "path" : "/",
          "code" : 200,
          "size" : 2502,
          "referer" : null,
          "agent" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
        }
      }
    ]
  }
}

このアクセスログはトップページへのものですが、その他のページについても順次ログが保存されていきます。

      {
        "_index" : "html-access-log",
        "_type" : "fluentd",
        "_id" : "OnojYWkBIj4IrKe-qslX",
        "_score" : 1.0,
        "_source" : {
          "host" : "172.17.0.1",
          "user" : null,
          "method" : "GET",
          "path" : "/getting-started.html",
          "code" : 200,
          "size" : 4747,
          "referer" : "http://172.17.0.2/",
          "agent" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
        }
      },

Fluentdのログに、HTMLのログが出力されていないことを確認。

$ $ grep apache.access.styles /var/log/td-agent/td-agent.log | grep '"path":' | grep -Ec '"path":"(/|[^"]+html)"'
0
$ grep apache.access.styles /var/log/td-agent/td-agent.log | grep '"path":' | perl -wp -e 's!.+"path":"([^"]+)".+!$1!; s!.+(\..+)!$1!' | sort -u
.css
.gif
.ico
.js
.png

Elasticsearch側も確認。

$ curl '172.17.0.3:9200/html-access-log/_search?q=*&pretty&_source=path'
{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 9,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "html-access-log",
        "_type" : "fluentd",
        "_id" : "PHojYWkBIj4IrKe-qslX",
        "_score" : 1.0,
        "_source" : {
          "path" : "/howto/auth.html"
        }
      },
      {
        "_index" : "html-access-log",
        "_type" : "fluentd",
        "_id" : "PXojYWkBIj4IrKe-qslX",
        "_score" : 1.0,
        "_source" : {
          "path" : "/vhosts/index.html"
        }
      },
      {
        "_index" : "html-access-log",
        "_type" : "fluentd",
        "_id" : "OXohYWkBIj4IrKe-QMnm",
        "_score" : 1.0,
        "_source" : {
          "path" : "/"
        }
      },
      {
        "_index" : "html-access-log",
        "_type" : "fluentd",
        "_id" : "P3ojYWkBIj4IrKe-qslX",
        "_score" : 1.0,
        "_source" : {
          "path" : "/stopping.html"
        }
      },
      {
        "_index" : "html-access-log",
        "_type" : "fluentd",
        "_id" : "OHogYWkBIj4IrKe-DMlO",
        "_score" : 1.0,
        "_source" : {
          "path" : "/"
        }
      },
      {
        "_index" : "html-access-log",
        "_type" : "fluentd",
        "_id" : "O3ojYWkBIj4IrKe-qslX",
        "_score" : 1.0,
        "_source" : {
          "path" : "/index.html"
        }
      },
      {
        "_index" : "html-access-log",
        "_type" : "fluentd",
        "_id" : "QHokYWkBIj4IrKe-_smY",
        "_score" : 1.0,
        "_source" : {
          "path" : "/vhosts/index.html"
        }
      },
      {
        "_index" : "html-access-log",
        "_type" : "fluentd",
        "_id" : "OnojYWkBIj4IrKe-qslX",
        "_score" : 1.0,
        "_source" : {
          "path" : "/getting-started.html"
        }
      },
      {
        "_index" : "html-access-log",
        "_type" : "fluentd",
        "_id" : "PnojYWkBIj4IrKe-qslX",
        "_score" : 1.0,
        "_source" : {
          "path" : "/stopping.html"
        }
      }
    ]
  }
}

いくつかアクセスしても、HTMLやトップページ(「/」)に対するアクセスのみが入ります。

大丈夫そうです。