以前、nginxのログをLTSV形式で出力して、fluentd経由でMongoDBに保存するの作業を実施したとき、ログの値がすべて文字列で保存されることに気付きました。
例えば、
- status
- bytes_sent
- body_bytes_sent
- request_time
- upstream_response_time
は、ストレージの省スペース化や検索インデクスのためにint
またはfloat
で保持するのが望ましいです。
HTTPステータスコードで正常なリクエストのみを対象とするには200番台に絞り込む必要があり、MongoDB上では次のようなクエリで検索することが出来ます。
> db.nginx_access.find({status: {"$gte": 200, "$lt": 300}})
しかし、文字列で保存されている場合は大小で比較することが出来ないので、文字列の先頭一致で検索する必要が出てきて面倒なことこの上ありません(クエリは割愛)。
fluentdにプラグインを追加して型変換を行うことで回避できます。型変換にはfluent-plugin-typecastを使います。td-agent利用時にfluent-plugin-typecast
をインストールするには次のようにします。
/usr/lib/fluent/ruby/bin/fluent-gem install fluent-plugin-typecast
fluent-plugin-typecast
をインストールすると、fluentdのtype
にtypecast
パラメタが使えるようになります。item_types
に、ログのキーと変換後の型をコロンでつなぎ、複数ある場合にはカンマで区切って列挙します。
先のパラメタをinteger, floatに変換するには次のようにします。
<match nginx.access>
type typecast
item_types size:integer,status:integer,request_time:float,upstream_response_time:float,bytes_send:integer,body_bytes_send:integer
tag filtered.nginx.access
</match>
変換後のログはfiltered.nginx.access
というタグをつけて処理します。
<match filtered.nginx.access>
type copy
<store>
type mongo
host 127.0.0.1
database server-log
collection nginx_access_log
</store>
</match>
出力されたログを確認してみます。
{
"_id" : ObjectId("53199b97b24cd85a6100004e"),
"remote_addr" : "xxx.xxx.xxx.xxx",
"request_method" : "GET",
"request_length" : "1607", // あっ
"request_uri" : "/ajax/mypage",
"https" : "",
"uri" : "/ajax/mypage",
"query_string" : "",
"status" : 200,
"bytes_sent" : 480,
"body_bytes_sent" : 95,
"referer" : "",
"useragent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36",
"forwardedfor" : "xxx.xxx.xxx.xxx",
"request_time" : 0.087,
"upstream_response_time" : 0.087,
"time" : ISODate("2014-03-07T10:11:34Z")
}
status
やrequest_time
が数値型になってますね!!!
めでたしめでたし。