fluentd

Fluentdのin_httpプラグインでJSONを受け取るときのTip

More than 1 year has passed since last update.

はじめに

fluentdのin_httpプラグインを使うと、一般的なHTTP POSTメソッドでJSONを投げ込むことでfluentdにデータを送ることができます。
その時に微妙に引っかかった点について書いていきます。

なお、ここではtd-agent-2.3.6-0.el6.x86_64を使用したときの話を書いているので後継バージョンで異なる可能性があります。

in_httpプラグインについて

ビルトインに含まれるプラグインで、HTTPで投げ込めます。

<source>
  @type http
  port 9880
  bind 0.0.0.0
  body_size_limit 32m
  keepalive_timeout 10s
  add_remote_addr true
</source>

上記のような設定時は以下のように投げ込むことでデータを入れられます。

curl -X POST -d 'json={"message":"TEST","user":"cuturn"}' http://example.com:9880/fluentd.tag.to -v

ポイントは、json={JSON} という形で投げ込むことです。また、in_httpプラグインはin_tailやin_tcpと違ってタグを送り元が決めることができることがポイントです。特にヘッダを指定する必要はありません。

ただし、上記設定はJSONデータ部分が誤っていても200OKが返ってしまうという問題があります。

普通にやるとJSONが間違っててもエラーを返さないので、少し設定を修正しましょう

通常通りの設定で動かすと、実はJSON文字列が多少間違っててもエラーレスポンスを返しません。json={}の形でさえあれば、200OKを返します。これはデバッグ上非常に宜しくありません。またlog_level debugとしたとしても、何のログもでてきません。

そこで、以下のようにformatを指定します。

<source>
  @type http
  port 9880
  bind 0.0.0.0
  body_size_limit 32m
  keepalive_timeout 10s
  add_remote_addr true
  format json
</source>

上記のように設定すると、以下のようなCURLで投げ込むことができます。json=は不要になりました。

curl -X POST -d '{"message":"TEST","user":"cuturn"}' http://example.com:9880/fluentd.tag.to -v

間違ったJSONを送った場合は、送信コマンド/応答含めて以下のような感じになります。

$ curl -X POST -d '{"message":"TEST","user":"cuturn",}' http://example.com:9880/fluentd.tag.to -v
...
> POST /log HTTP/1.1
> Host: example.com:9880
> User-Agent: curl/7.56.1
> Accept: */*
> Content-Length: 35
> Content-Type: application/x-www-form-urlencoded
>
...
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 400 Bad Request
< Content-Type: text/plain
< Connection: Keep-Alive
< Content-Length: 80
<
400 Bad Request
Received event is not json: {"message":"TEST","user":"cuturn",}
* STATE: PERFORM => DONE handle 0x600057950; line 1993 (connection #0)
* multi_done
* Connection #0 to host example.com left intact
* Expire cleared

というわけで、必ず安定してjsonを送れる自信があるならいいですが、フォーマット間違えたときにきちんと失敗した旨受け取りたい場合はformatを指定するよう設定しましょう。

HTTPS化したいとき

HTTPSで受け取りたい場合は、同サーバ上にNginxを立ててリバースプロキシするのがオススメになります。以下のような設定を/etc/nginx/conf.d/に置くことで、Nginx経由でfluentdへの通信が通るようになります。cipherとかログ設定とかSSLとかは適宜どうにかしてください。

### /etc/nginx/conf.d/fluentd.conf
server {
    listen                      443;
    server_name                 example.com;

    ssl                         on;
    ssl_certificate             /etc/nginx/ssl/server.crt;
    ssl_certificate_key         /etc/nginx/ssl/server.pem;
    ssl_protocols               TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers                 HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers   on;

    #charset koi8-r;
    access_log  /var/log/nginx/fluentd.access.log  main;

    location / {
        proxy_set_header Host             $host;
        proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_pass http://localhost:9880/;
    }
}

なお、X-Forwarded-Forヘッダを設定することでFluentdはREMOTE_ADDRフィールドにこのヘッダ内容を入れてくれます。これでばっちり送信元情報が使えます。BIG-IPや他のLoadBalancerを導入する場合も、同じ考え方をしてください。

またin_httpプラグインはtd-agent.logにアクセスログを出してくれないので、アクセスログが欲しいというだけであったとしてもNginxを立ててリバースプロキシする価値はあるかもしれません。