はじめに
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を立ててリバースプロキシする価値はあるかもしれません。