ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

td-agent(Fluentd) を利用したログ収集

はじめまして! 仕事内容がわかりにくいインフラエンジニアのすずきです。

先日このブログにて弊社田渕が書いていましたが、 昨年Ruby biz Grand prix 2016で審査員特別賞をいただくことができとてもありがたく思います。

Ruby biz Grand prix 2016 - ユニファ開発者ブログ

この賞を頂いたからというわけではないですが、
いろんな方に弊社サービスを安心して快適に利用していただけるように日々頑張っていかねばと改めて思った次第です。

そういえば、Ruby biz Grand prix といえば前回大賞となったトレジャーデータ株式会社様、 弊社でも一部で恩恵をうけているので軽く紹介できればと思います。

ただサービスではなく、公開していただいているFluentdのパッケージ版td-agentを利用させていただいているといった感じです。

Fluentd とは

Fluentd はログの収集、集約やデータの収集、集約、プラグインを利用した集計などなど ログやデータの収集にまつわるものならなんでも出来ちゃいそうなツールです。
プラグインによる拡張ができるので必要な機能が必要であれば自分で作ることも可能です。

今回Fluentdの事を書いていますが、検索すれば設定例などは沢山出てくるとおもうので一つの例として見ていただけたらなと思います。

ログの収集の方法

Fluentdの利用はまだログの収集がメインになっています。
弊社エンジニアもログの集約サーバでログを見てもらっているかなと思いますが、
裏でFluentdが動いてる事を知ってる方は少なそうなのでこの場を借りて共有しておこおうかなと思います。 ※詳細は別途勉強会で

構成としては単純で以下の2種類になります。

  • サービス用のサーバ群
    • ログ収集の設定がされたFluentd
  • ログ集約サーバ
    • ログ集約用の設定 がされたFluentd

ログ収集の設定

ログ収集ならトレジャーデータ株式会社の田籠さんの作られたfluent-agent-liteや、株式会社カヤックのfujiwaraさんの作られたfluent-agent-hydraなどもあるのですが、 これらは軽量なのですがツール停止時点からログ収集を再開することができなさそうだったので収集もFluentdを利用しています。

サンプルとしてWebサーバのログ収集設定を用意してみました。(fluentdハイライト何が良いんだろ、とりあえずshが見やすそうでした)
なお利用しているFluentdのバージョンはちょっと古くて申し訳ないのですが0.12系です。
設定の説明はコメントとして追記しています。
また、これから出てくるpathの値などは適当な値を羅列しているだけなので、 試される方はご自分の環境にあわせて変更してください。

<source>
  @type tail
  ## apacheのアクセスログはltsvにしているのでltsvフォーマットで収集するようにしています。
  format ltsv
  path /var/log/httpd/access_log
  tag httpd.access_log
  pos_file /var/log/td-agent/httpd-access.log.pos

  ## Fluentdのデータのやりとりにはtimeフィールドがつくいているのですが、time_formatをつけることでFluentdが処理した時間ではなく、
  ## ログのtimeフィールドの時刻を利用してFluentdを処理できます。
  time_format %d/%b/%Y:%H:%M:%S %z
  read_from_head true
  rotate_wait 60

  ## TAILラベルをつける
  @label @TAIL
</source>

<source>
  @type tail
  ## errorログなどフォーマットが決まっていないものがあるのでnoneフォーマットで収集するようにしています。
  format none

  ## pathにワイルドカードを利用して全てのログを対象に収集します。
  ## 弊社ではログローテーションしたものはOLDフォルダに移動させているので、
  ## OLDフォルダと先頭で収集設定を入れたアクセスログを exclude_path に追加して2重で収集されないようにしています。
  path /var/log/httpd/*
  exclude_path ["/var/log/httpd/OLD", "/var/log/httpd/access_log"]

  ## 収集対象がワイルドカードするとpathの/を.に変えたものがタグとして付与されます。
  ## 今回の場合だと/var/log/httpd/error.logの場合 httpd.var.log.httpd.error.log というタグが付与されることになります。
  tag httpd.*
  pos_file /var/log/td-agent/httpd-other.log.pos
  read_from_head true
  rotate_wait 60

  ## TAILラベルをつける
  @label @TAIL
</source>

<source>
  @type tail
  ## こちらはRailsのログですがapacheのログ収集と同じく不要なものを除いて全て収集します。
  format none
  path /www/rails/web/shared/log/*
  exclude_path ["/www/rails/web/shared/log/OLD",  "/www/rails/web/shared/log/newrelic_agent.log"]
  tag web.*
  pos_file /var/log/td-agent/web.log.pos
  read_from_head true
  rotate_wait 60
   ## TAILラベルをつける。
  @label @TAIL
</source>


## TAILラベルのついたデータは全てログ集約サーバに転送するようにします。
## 古いFluentdでは httpd.**,web.**など書いてタグによる処理を書かないといけませんでしたが、
## 0.12から追加されたlabelでそのようなことをしなくてよくなりました。
<label @TAIL>
  <match **>
    @type forward
    flush_interval 1s
    <server>
      name log-server
      host 10.0.0.251
    </server>
  </match>
</label>

ログ収集ではこのような設定を利用しています。
path*を利用できるとはかいてあったのですが、 利用している記事などはあまりみかけなかったのでこんな感じかな?といった感じで設定を作っています。
path*を利用している理由ですが、サーバアプリのログが固定ではないからです。
固定というと語弊がありますが、必要に応じでてサーバアプリ側でログが追加されたり消されたりするためです。
その度にFluentdの設定変更対応をする為の連携を取るのもお互いに無駄かと思い手離れしやすいようにこの設定にしました。

ログ集約用の設定

先程収集されて、転送されてきたデータを受け取るログ集約サーバ側の設定サンプルも用意しました。

## サーバサーバに転送されてきたログをすべてにlogsラベルをつけています。
## 別のサービスからデータを受け取る場合はポートを変更して別のラベルをつけるなどの対応が必要です。
<source>
  @type forward
  @label @logs
</source>

<label @logs>
  ## apacheのアクセスログのみなので受け取ったログをファイルにおとすよくある設定にしています。
  <match  httpd.access_log>
    @type file

    time_slice_format %Y%m%d%H
    compress gz
    format ltsv
    include_time_key true
    buffer_chunk_limit 1g
    path /data/log/httpd/access_log
    symlink_path /data/log/httpd/httpd.access_log
  </match>

  ## apacheのアクセスログ以外すべて受け取っているのでfluent-forest-pluginを利用しています。
  ## このプラグインを利用することでタグに応じた設定がかけるので楽です。
  ## そうでない場合上記のapacheのアクセスログを同じような設定をログの数だけ用意する必要があって非常に面倒ですし、
  ## ログが増えるたびに設定を追加するなどの作業が発生します。
  <match {httpd,web}.**>
    @type forest
     subtype file
    <template>
       time_slice_format %Y%m%d%H
       compress gz
       format single_value
       add_newline true
       message_key message
       buffer_chunk_limit 1g
    </template>

    <case httpd.**>
       path  /data/log/httpd/__TAG_PARTS[0]__/__TAG_PARTS[-1]__
       symlink_path /data/log/httpd/__TAG_PARTS[0]__.__TAG_PARTS[-1]__     
    </case>

    <case web.**>
        path  /data/log/rails/__TAG_PARTS[0]__/__TAG_PARTS[0]__/__TAG_PARTS[-2]__.log
        symlink_path /data/log/rails/__TAG_PARTS[0]__/__TAG_PARTS[0]__.__TAG_PARTS[-2]__.log
    </case>
  </match>

__TAG_PARTS[0]__,__TAG_PARTS[1]__とありますが、 これらはタグを.で区切った配列とみなしてその情報を利用しています。

path  /data/log/rails/__TAG_PARTS[0]__/__TAG_PARTS[0]__/__TAG_PARTS[-2]__.log

コレはどういうことかというと web.app.error.logのタグが付いたデータは/data/log/rails/web/web/error.logに吐き出されるということです。

今回fluent-plugin-forestを利用したログ収集の設定を書きましたが、 v0.12からこのプラグインが無くてもいい感じに書けそうみたいなのを見た気がするのですがやり方が思いつかなかったので現在も利用しています。

ご存じの方居たらお知らせ頂けたらと思います。

さいごに

今回Fluentdの弊社の利用方法をすこし紹介させていただきました。
だれか1人の方にでも参考にしていただけたら幸いです。

他にもAWSサービスの連携や、文字列から条件分岐してSlackに通知するなどやっていたりもします。
またの機会があれば紹介させていただこうと思います。

弊社はZabbixでログ監視もしていますが可能ならいつかFluentdを利用したログ監視に移動したいなとはおもっています。
Zabbixはログ監視の追加が面倒なので………
そういった話も書けていけたらと思っています。

引続き弊社ブログよろしくお願いします。

すずき