woshidan's blog

そんなことよりコードにダイブ。

fluentdについてのメモ

fluentdとは

参考: https://docs.fluentd.org/v0.12/articles/quickstart

基本Cで書かれていてRubyの薄いラッパーがあるログ収集用のライブラリ。 Fluentdは入ってきたログをJSONとして扱う。

インプットプラグインとアウトプットプラグイン

参考: https://docs.fluentd.org/v0.12/articles/quickstart 参考: https://docs.fluentd.org/v0.12/articles/life-of-a-fluentd-event

Fluentdには

  • 入力を受け付け、入力されたデータをFluentd上で共通して扱える形式であるJSON + αに加工するインプットプラグインと、
  • インプットプラグインから出力されたデータを他の場所へ時刻などをつけて整形したりフィルタリングしたりして出力するアウトプットプラグイン

がある。どのプラグインを使用するかは .conf の拡張子を持った設定ファイル(デフォルトでは fluent.conf. 詳しいパスは https://docs.fluentd.org/v0.12/articles/config-file )にxmlのような形で書いていく。

インプットプラグインは、source 要素を使い、種類(@type)と種類に対応したパラメータを指定することで、IP, ポート, 流れてきたデータの加工方法を指定される。

たとえば、 https://docs.fluentd.org/v0.12/articles/life-of-a-fluentd-event の例の

<source>
  @type http
  port 8888
  bind 0.0.0.0
</source>

では、 localhostTCPポート 8888 番から json=<JSON文字列> のボディを持つHTTPリクエストがきたら、Fluentdで扱えるJSONのデータが内部で取れる、ということになる。

アウトプットプラグインは、match 要素を使い、インプットプラグインが出してきたJSONのデータをフィルタリングしたり、特定のキーの値を加工したり、別のファイルや標準出力へ出力したりする。

match tag のように書くことで、特定のタグを持ったログのみを出力に渡すことができて、むしろフィルタリングしない場合も ** など、なにかしら書かないといけない。

また、 https://docs.fluentd.org/v0.12/articles/life-of-a-fluentd-event の例を眺めてみると

<match test.cycle>
  @type stdout
</match>

となっていて、 test.cycle のタグがついたログだけを標準出力((これは @type stdout の指定による。標準出力へログを出すアウトプットプラグインを使う、という意味))に出す、という意味になる。

インプットプラグインにより、ログがJSONとして扱えるよう加工されている

参考: https://docs.fluentd.org/v0.12/articles/life-of-a-fluentd-event

Fluentdは入ってきたログをJSONとして扱う というのを読んだ時、一瞬JSONの形でFluentdに渡さなければいけないのかと思ったのですが、そんなことはない。

たとえば、Apache のログが /var/log/httpd-access.log のパスで以下のような形式になっているとして

192.168.0.1 - - [28/Feb/2013:12:00:00 +0900] "GET / HTTP/1.1" 200 777

fluent.conf で入力元を Apache のログとするように

<source>
  @type tail
  format apache
  path /var/log/httpd-access.log
  tag apache.access
</source>

のように適切にプラグインの指定をすれば、このsourceから出てきたログを受け付けるアウトプットプラグインを書く時は、JSONのキーを加工して... みたいな感じでパラメータの指定ができる。

便宜上、Fluentdの上ではJSONとして扱う、と言ってますが、sourceで指定したインプットプラグインから出力されるデータは Event と呼ばれていて、JSON形式のデータ以外に、時刻とタグがつく。

Eventを複数の出力へ送る

参考: https://qiita.com/nagais/items/ca96af840b8061102551 参考: https://docs.fluentd.org/v1.0/articles/out_copy

基本的にログを加工して送る先は1つだと思うんですが、タグAがついたログとタグBがついたログは別のS3のバケットに送りたい、とかそういう場合は out_copy プラグインを使う。

<match pattern>
  @type copy
  <store>
    @type file
    path /var/log/fluent/myapp1
    ...
  </store>
  <store>
    ...
  </store>
  <store>
    ...
  </store>
</match>

一旦 out_copy プラグインを使うmatch要素でsourceから来た入力を受けて、store 要素で指定した別のmatch要素に送り直す形となる。

Eventをフィルタリングしたり、加工する

参考: https://docs.fluentd.org/v1.0/articles/life-of-a-fluentd-event#filters 参考: https://docs.fluentd.org/v1.0/articles/filter_record_transformer

全部のログを取ると多すぎるので、注目したいイベントのログだけ保管用のストレージへ転送、といったこともなくはないと思うけれど、そういう場合は filter 要素を使って書くフィルタープラグインを使う。

filter 要素は source 要素と match 要素の間に書くみたい。

また、Fluentdはログの転送だけじゃなくて加工も行うのだが、加工を行う場合もフィルタープラグインを使い、代表的なものが record_transformer プラグイン

たとえば、

<filter foo.bar>
  @type record_transformer
  <record>
    adding_key "Sample"
  </record>
</filter>

のようにすれば、EventのcontentsのJSON"Sample" という値の adding_key というキーが追加される。

現場からは以上です。