LTSV のもうひとつのメリット、あるいは、プログラムでログを出力する際に気をつけるべきこと

Labeled Tab-separated Values (LTSV) がブームのようです。

LTSV については、ラベルをつけることで柔軟に拡張できるという点が、その特徴として取り上げられますが、もう一点、タブをセパレータに使うことでログのパースが簡単になった、という点を忘れるべきではないでしょう。

特に httpd のログは NCSA httpd という HTTP/0.9 時代のWebサーバのログフォーマットがベースに拡張されてきたため、以下のようにセパレータとして空白、[]、ダブルクォート ("")*1が混在するという、とても処理しづらいものになっていました。どれほど複雑かは「404 Blog Not Found:perl - Apache Combined Log を LTSV に」の実装を見れば明らかでしょう。

127.0.0.1 - - [08/Feb/2012:23:52:42 +0900] "GET /favicon.ico HTTP/1.1" 404 209 "-" "Mozilla/5.0 AppleWebKit/534.10 Chrome/8.0.552.215 Safari/534.10"

これに対し、LTSVはタブをセパレータに使うことで、ログのパースがとても簡単になっています。

time:28/Feb/2013:12:00:00 +0900<TAB>host:192.168.0.1<TAB>req:GET /list HTTP/1.1<TAB>status:200

えっ? タブがログの、User-Agent 等の文字列中に現れることはないのかって?

ありません。

というのは、かつて、Apacheに送信するHTTPリクエストに制御文字を含めることでサーバ運用者に対して攻撃が可能になるという脆弱性*2が発見され、その結果として Apache のログにおいては制御文字が全てエスケープされるようになったという経緯があるのです。

タブ(という制御文字)をセパレータに用いる、というLTSVの手法は、この脆弱性対応の副産物として生まれた、そしてそれがゆえに汎用性をもったアプローチなのです。

また、上にあげたように、プログラムからユーザー由来の文字列を含むログを出力する際は、適切なエスケープを行わないと脆弱性として取り扱われる可能性がありますので、注意が必要です*3

PS. あと、今からLTSVでhttpdのログを扱い始めるなら、リクエストを「req:GET / HTTP/1.0」のように単一のフィールドに入れるのは避けるべきだと思います。HTTP/2.0 になった時に対応できない可能性があるので…*4

*1:ダブルクォートされた文字列中においては " は \" にエスケープされる

*2:http://www.juniper.net/security/auto/vulnerabilities/vuln9930.html

*3:個人的には、それってログを表示する側の問題じゃないかと思いますが

*4:こういうなのを技術的負債って言うんですか?