Fluentd v0.12の目玉機能としてFilterとLabelがある. この機能の導入にあたってはメッセージのルーティングを行う部分のコードがガラリと変わっているはずなので、興味本位で読んでみた.
機能についての参考文書
そもそもFilterやLabelって何?というあたりは以下が参考になる。
- Fluentd v0.12でのFilterとLabel
- Fluentd v0.12 is Released
- Fluentd v0.12の目玉機能らしいFilterを試してみた
- Fluentd v0.12 ラベル機能の使い方とプラグインの改修方法
v0.10ではどうだったか
Matchクラスがmatch
ディレクティブで宣言されたタグのパターンと、行き先のOutputクラスを保持していて、EngineClass#emit
(最終的な呼び出し先はemit_stream
)で該当するMatchを探し出し、そこに向けてemit
する、という形だった.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
なので、ルーティングを管理するテーブルはEngineClass
の@matches
一つだったし、tagがルーティングのキーになっていた. 複数のOutputで順番に処理したい場合は都度tagを書き換えていく必要があった.
v0.12の場合
Agent
, RootAgent
, Label
, EventRouter
と言った新しいクラスが導入されている.
Label
- 各
label
ディレクティブの中に存在するFilterおよびOutputプラグインを管理するクラス
- 各
RootAgent
label
ディレクティブに属さない(設定ファイルのルート直下にある)Input, Filter, Outputプラグイン、および各Labelクラスを管理するクラス
Agent
RootAgent
およびLabel
の親クラス.
EventRouter
- ルーティングのためのルール(どのタグパターンに対して、どのようなfilterやmatchが存在するか)を管理し、イベントのルーティングを行うクラス
RootAgent
およびLabel
のインスタンスは、それぞれ自分自身が管理する範囲のルーティングを行うEventRouter
クラスのインスタンスを保持している.
以下、実際のコードを見てみる.
起動部分
まずは、configurationを読み込んでいく段階でどのようなクラスが生成されていくのかを見てみる.
Supervisor#start (init_engine)
Supervisorが起動して、色々と準備していく部分. init_engine
内で Engine#init が呼ばれ、ここでRootAgent
が生成される.
RootAgent
の親クラスであるAgent
のコンストラクタは以下のようになっている
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
自身が管理するOutputクラス、Filterクラス達を保持するための変数が存在している. また、そのスコープでのルーティングを行うEventRouter
クラスをここで生成している.
RootAgent
については、これに加えて更にInputやLabelクラスも管理するような構造になっている. (root_agent.rb)
Supervisor#start (run_configure)
Supervisor#run_conigure
が呼ばれると、Engine#configure
を経由してRootAgent#configure
が呼ばれる.
ちょっと長いが引用.これにより以下が行われる
- labelディレクティブがあった場合
- add_labelにより新規
Label
オブジェクトを生成 - さらに、その
Label
オブジェクトのconfigure
を呼び出す.configure
の内容については、以下のAgent#configure
を参照.
- add_labelにより新規
- sourceディレクティブがあった場合
- add_sourceによりInputプラグインのインスタンスを生成
- Inputプラグインがemitする際の投げ先として、以下を登録.
- そのInputプラグインで
@label
が設定されている場合→設定されたLabel
オブジェクトのEventRouter
を登録 - それ以外の場合→
RootAgent
のEventRouter
を登録
- そのInputプラグインで
Inputプラグインについては@label
が設定されている場合とそうでない場合で、emit先のEventRouter
を切り替えることができるようになっている.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
さらに、RootAgent
の親クラスであるAgent#configure
では同様にmatchに対してadd_match
、filterについてadd_filter
が呼ばれる.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Agent
はLabel
の親クラスでもあるので、新しいLabel
オブジェクトのconfigure
が呼び出された際もこのコードが実行されることになる.
add_filterやadd_matchが何をしているかというと、そのAgent
が持っているEventRouter
に対してルーティングのルール(Rule
オブジェクト)を登録している.
絵にすると、、、
FluentdのBlogに書かれているサンプルを元に、どんな感じのオブジェクトたちが出来上がるかを絵にするとこんな感じ.
labelごとにルーティングテーブルを持つので、labelが違えば異なるルールでルーティングする、ということができるようになる.
emitの動き
ここまでで、各Input, Filter, Outputプラグインインスタンスは、自分がemitする先のEventRouter
オブジェクトを知っていることになる.
まず、Inputプラグイン内では自分が知っているEventRouter
にemit
する.
1
|
|
emit
はemit_stream
に飛ぶので、以下のコードが呼び出される. match
メソッドが返してきたオブジェクトに対してemit
する.
1 2 3 4 5 |
|
EventRouter#match に飛ぶ. match
はemitされたtagを受け取るべきCollectorを返す.
1 2 3 4 5 6 |
|
このCollectorを探す部分がどうなっているかと言うと、
こんな感じになっている. つまり、Filterが使われていればPipeline
オブジェクトを生成してそこにFilterやOutputを順次追加していく. FilterがなければPipeline
の代わりにOutputを直接返す.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
よって、emit
されたレコードはPipeline
またはOutput
にemit
されることになる. そして、Pipeline
にemit
された場合は以下のコードに辿り着き、順番にFilterを通った後に最終的にOutputにemit
されることになる.
1 2 3 4 5 6 7 |
|
このようにFilterを実現するためにPipelineという新しい仕組みを導入しているため、tagの書き換えによる多段フィルタをしなくて済むようになっている.
まとめ
- v0.12のLabel, Filterを実現している部分のコードを読んでみた
- Labelの部分は、RootAgent(設定ファイルのROOT部分)および各labelディレクティブごとにルーティングテーブル(
EventRouter
)を分けることにより実現されている - Filterは、レコードに対する連続した処理を表現する、Pipelineという新たな仕組みを導入することで実現されている