fluentd-tcp-capturerを使ってFluentdのTCP inputに流れてくるメッセージをデバッグする

WebアプリやIoTデバイスが吐くログをFluentdに集約する環境を構築したり運用していると、次のようなことをやりたくなってきます。

- Fluentdに流れてくるメッセージの中身を確認したい
- メッセージを別のconfに流して動作を確認したい

これらのことをやろうとすると、場合によっては今動いているconfをいじったり、Fluentdを再起動したりする必要がでてきます。
しかしながら、matchが定義されていないtagだったらconfをいじらなくてはいけないし、*type stdout*を加えるためだけにそれをやるのは手間だし、もう少し気軽に新しい設定を試したかったりします。さらに、それがproduction環境であれば、ちょっと設定を変えてみる、とかはあまりやりたくなかったりします。

そこで、`fluentd-tcp-capturer`(https://github.com/takumakanari/fluentd-tcp-capturer) というツールを作りました。

## What

TCPでFluentdに流れてくるパケットをキャプチャします。

キャプチャしたパケットを、Fluentdのメッセージに変換して表示したり、別のFluentdに流したりします。


## Usage

### Setup

gemをインストール

```shell-session
$ gem install fluentd-tcp-capturer
```

`fm-cap`というコマンドが使えるようになります。

```shell-session
Usage: fm-cap [options]
    -d, --device DEVICE              Device name [default: eth0]
    -p, --port PORT                  Fluentd port to capture [default: 24224]
        --forward-host HOST          If set, message will be forwarded to other Fluentd host
        --forward-port PORT          Fluentd port to forward message (used when --forward-host is set)
        --debug                      Set loglevel DEBUG
```


テスト用のFluentdを次のような設定で立ち上げておきます。

```
<source>
  @type forward
</source>

<match test.**>
  @type stdout
</match>
```

### メッセージをDumpする

別のターミナルで`fam-cap`を立ち上げ、eth0/24224に流れてくるFluentd宛のメッセージをキャプチャします。
内部でpcapを利用しているので権限がいります。

```shell-session
$ sudo fm-cap
I, [2017-03-03T22:41:31.141436 #14088]  INFO -- : Start capturing eth0/port=24224
```

もう一つ別のターミナルを立ち上げて、fluentdにメッセージを流してみます。

```shell-session
$ echo '{"message" : "hello"}' | fluent-cat test.hoge
```

そうすると、Fluentdのstdoutとは別に、fm-cap側でもメッセージがdumpされるのがわかります。

```shell-session
$ sudo fm-cap
I, [2017-03-03T22:41:31.141436 #14088]  INFO -- : Start capturing eth0/port=24224
2017-03-03 13:41:34 +0000 | tag=test.hoge msg={"message"=>"hello"}
```

captureするnetwork deviceやFluentdのportはオプションで指定することができます。

```shell-session
$ sudo fm-cap -d lo0 -p 4567
```

### メッセージを別のFluentdに転送する

`--forward-host`、`--forward-port`を指定すると、captureしたメッセージを、他のFluentdに転送することができます。
* 現時点で、全くセキュアな実装になっていない(TODO)ので、実行環境によっては注意が必要です,,

もう一つ、別のFluentdを立ち上げておきます。

```
<source>
  @type forward
  port 34224
</source>

<match fuga.**>
  @type file
  path /var/log/fuga
  time_slice_format %Y%m%d
  time_slice_wait 10m
  time_format %Y%m%dT%H%M%S%z
</match>
```

`fm-cap`を立ち上げます。

```shell-session
$ sudo fm-cap --forward-host localhost --forward-port 34224
I, [2017-03-03T22:46:31.878876 #14564]  INFO -- : Start capturing eth0/port=24224
```

これで、24224に流れてきたメッセージが、34224でlistenしている別のFluentdにも転送されるようになります。

```shell-session
$ echo '{"message" : "hello"}' | fluent-cat fuga.hoge
```

```shell-session
$ sudo fm-cap --forward-host localhost --forward-port 34224
I, [2017-03-03T22:46:31.878876 #14564]  INFO -- : Start capturing eth0/port=24224
I, [2017-03-03T22:46:34.577661 #14564]  INFO -- : Forwarded message to other-fluentd-node:4567
```

この例だと、24224で待っているFluentdには、tag `fuga.**`のmatchが設定されていないので何も出力されませんが、新たに立ち上げた34224では拾われて、ファイルにメッセージが出力されます。

## まとめ

- まだまだbuggyなのと、例えばdumpするときのtimestampのtimezoneが指定できなかったり等、いろいろ改善の余地があります

- (おそらく)secure forwardには使えません。また使うべきではない。。

- 内部的に走っているのはpcapを利用したパケットキャプチャなので、実行する環境によってはパフォーマンスに影響をあたえる場合があり、考慮が必要です。

## TODO

- httpとか別のprotocolにも対応できるとよい
- もう少しsecureにしたい