Hatena::ブログ(Diary)

naoyaのはてなダイアリー

February 09, 2013

LTSV FAQ - LTSV って何? どういうところが良いの?

LTSV って何?

Labeled Tab-Separated Values という、テキストのフォーマットの仕様です。CSV や TSV や JSON そのほかと同じ、テキストデータのフォーマット名。主にログ、特に httpd のアクセスログなどに適用すると便利です。

仕様は http://ltsv.org にまとまっています。随時更新中です。

LTSV は単なるログのフォーマットであって、それ以上でもそれ以下でもありません。

LTSV ってタブ区切りで値に名前を付けただけのもの?

はい、そうです。

これが

127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "http://www.example.com/start.html" "Mozilla/4.08 [en] (Win98; I ;Nav)"

こうなります。

host:127.0.0.1<TAB>ident:-<TAB>user:frank<TAB>time:[10/Oct/2000:13:55:36 -0700]<TAB>req:GET /apache_pb.gif HTTP/1.0<TAB>status:200<TAB>size:2326<TAB>referer:http://www.example.com/start.html<TAB>ua:Mozilla/4.08 [en] (Win98; I ;Nav)

ただのログフォーマットが何で今話題になっているの?

Apache の access_log で広く使われていた combined ログフォーマットが意外と parse しづらい、値の追加に対して弱いといった欠点はあったものの、歴史的経緯もあってみんなそれを使い続けてきたところ案外簡単な変更で各種問題が解決できるというコロンブスの卵的発想の仕様だったからです。

昨今のログ解析の重要性の高まりにともなって、アクセスログに標準では出力されない値を追加したり変更頻度の高い要求仕様があるログの出力に迫られたりと、既存のログフォーマットでは対応しづらい要件が増えてきていたところにうまくはまったという背景もあるでしょう。

盛り上がりの経緯については 【今北産業】3分で分かるLTSV業界のまとめ【LTSV】 - naoyaのはてなダイアリー にまとめています。

LTSV は何がいいの?

  • parse しやすい。ruby なら Hash[gets.split("\t").map{|f| f.split(":", 2)}]
  • 特別な parser を必要としない
  • 出力時も、特別なフォーマッタを必要としない。Apache / nginx の組み込みの設定ファイルで設定できる
  • 新しいフィールドの追加に対して開かれている。より簡単に言うと、新しい列を追加しても既存のプログラムに影響を与えない
  • 値に名前がついているので、parse 後料理しやすい
  • 行指向なので他のプログラムとも組み合わせやすい

詳しくは Labeled Tab Separated Values (LTSV) ノススメ - stanaka's blog LTSV が行指向な Key-Value フォーマットで捗る話 - naoyaのはてなダイアリー を見ていただくと良いと思います。

「拡張に対して開いている」ってどういうこと?

例えば

host:127.0.0.1<TAB>ident:-<TAB>user:frank<TAB>

という LTSV フォーマットのログがあったとします。これを

#!/usr/bin/env ruby

while gets
  record = Hash[$_.split("\t").map{|f| f.split(":", 2)}]
  # record に対して何がしかする
end

とパースして処理した似たようなスクリプトが 100 種類くらい手元にあることを想像してください。

ある日、ログに時刻がないことが気づいて時刻を追加したいと思いました。

time:[10/Oct/2000:13:55:36 -0700]<TAB>host:127.0.0.1<TAB>ident:-<TAB>user:frank<TAB>

このとき、既存の 100 種類のスクリプトは壊れて動かなくなるでしょうか。なりませんね。これがもし、combined フォーマットで正規表現などで parse していたとしたら、スクリプトは動かなくなります。

また、time フィールドは先頭でも末尾でも、あるいは真ん中に挿入するでも 100 種類のスクリプトはそのまま動作します。更にスクリプトが、record ハッシュに値が追加されることを考慮した処理になっていればログに time フィールドを追加しただけで、その瞬間からスクリプトが時刻も加味してくれるようになります。

逆に LTSV の欠点は?

combined ログと比較すると

  • combined ログよりも若干可読性が悪い
    • combined ログが可読性が良いかどうかは別として・・・
  • フィールド名分のサイズが増える

といったところです。ただしいずれの欠点も解決できる & 気にならない、と思っています。後述。

JSON の方が構造化もできるし良さそうだけど

データへの名前付けという点では JSON や MessagePack は良いのですが、parse がそこまで容易ではありません。また JSON はともかくとして特殊なフォーマットの場合既存の実装、例えば Apache や nginx から出力しようとしたときに工夫が必要になってしまいます。

LTSV は、なるべく手間をかけずに拡張性の低いログフォーマットから移行できるというバランスの良さがウリだと思います。

エスケープは仕様に入っていなくてもいいの?

LTSV の仕様としてはキーに区切り文字である ":" を使わない、タブで区切る、というぐらいしか仕様にはありません。エスケープは仕様に入っていません。エスケープが仕様にないことには理由があます。

ltsv.org を見ると、すでに各言語毎の LTSV 実装がたくさんありますが「ちょっと LTSV を処理したいな」という程度のときはそれらを使うまでもなく

#!/usr/bin/env ruby

while gets
  record = Hash[$_.split("\t").map{|f| f.split(":", 2)}]
  p record
end

だけで ok です。この容易さと先のエントリを加味するとエスケープ仕様は必要なさそうです。別途、より厳密な strict-LTSV のような追加仕様があってもいいかもね、という議論はあります。

アクセスログ以外にも適用していいの?

もちろん。CSV や TSV や JSON のようなただのフォーマットの仕様なので、適用範囲は自由です。

ラベル (キー) の名前は適当でいいの?

はい、適当でかまいません。

適当で構いませんが、アクセスログに適用する場合は ltsv.org にある "Recommendations for labeling" を採用するのも良いと思います。考える手間が省けますし、その他と揃っていると何かと便利です。

LTSV にするとちょっと出力が見づらくなっちゃうな〜

ltsview のようなフィルタを適用すると良いでしょう。フィルタの実装もとても簡単です。

こういうフィルタがあれば

$ tail -f access_log | ltsview

と、整形しながら tail するなどができます。見るときは今まで通り combined フォーマットが良い、というのであれば LTSV を combined フォーマットに変換するフィルタを書いてしまうのでも良いでしょう。

フィルタが簡単に実装できるのは、LTSV が行指向かつ自己記述的で拡張に開いているという、Unix 的発想に基づいた仕様であるところの賜・・・と言えるでしょう。

ログのサイズが少し大きくなってしまうのは大丈夫?

これは個人的意見でコンセサンスの取れているものではありませんが、

  • access_log の場合、リクエストURIやUser-Agent、リファラの文字列長が支配的でラベル名の増加分は気にする程ではない
  • ほんの少しの変更による access_log の増加が無視できないほどの大規模環境では、大規模ログの解析・保存に対してもっと別のソリューションを持っていることがほとんど
    • MapReduce (Hadoop や Amazon EMR) で解析する、ログはデータウェアハウスに転送して保存する ・・・ など
    • また、fluentd などを経由してログをデータベースなどに入れた場合、その時点で LTSV の label 分のサイズ増加は相殺される

といった点が挙げられると思います。少なくてもはてな社では3年以上使い続けているということで、はてなくらいの規模でも問題ないということは言えると思います。

fluentd 周りで話題になっているようだけど LTSV は fluentd 向けの仕様なの?

いいえ。

LTSV は単なるフォーマットの仕様だけで、その他のソフトウェアとは関係ありません。fluentd で話題になっているのは、fluentd が Apache や nginx のアクセスログを処理するのに良く使われるからです。LTSV を導入すると fluentd の設定が簡潔に、且つ DRY になるので今まで管理者を悩ませていた(長期運用時には割と面倒な)問題がひとつ解決されます。

既存の combined ログを LTSV に変換したい

404 Blog Not Found:perl - Apache Combined Log を LTSV に に perl スクリプトがあります。

特に外部ライブラリなどは利用していないスクリプトなので perl さえあれば使えます。このように、特殊な実装を用いなくても料理できるのも LTSV の良いところです。

誰が仕様の決定者なの?

この手の仕様の広まりであるように、特に「誰それが意志決定者である」という決まり事は一切ありません。面白いな、乗っかろう・・・と思った人たちが各自勝手にいろいろやっています。偉そうに FAQ を書いている自分にも、特に何かしらの権利そのほかがあるわけではありません。

一応、ltsv.org ドメインを持っていて最初の発案者である @stanaka を中心に話が進んでいるというのはありますが、ltsv.org のレポジトリは公開されていますし、誰でも参加できます。

インターネットって面白いですね!

動向を追いかけるにはどうしたらいい?

Twitter で ltsv で検索するとよさそうです。ハッシュタグがついてないツイートも多いので、ハッシュタグよりも、ただのフリーワード検索のほうがよさそう。LTSV という名前の検索性が良い。

日本国内の一部だけで話題になっているようだけど

そうですね。できれば広く、またグローバルに広まって欲しいところです。この手の仕様は広く多くのところで使われるほど、その価値は高くなります。

例えば本エントリを翻訳して ltsv.org の管理者である @stanaka に送るあるいは Pull Request するとみんなが幸せになるでしょう。Hacker News に投稿するなども良いと思います。

自分も何かしらコミットしたい

先の通り、特に意志決定者が誰それということはありませんので、ブログに書いてもいい、パーサーの実装を作って #ltsv つきでツイートするでもいい、英語のドキュメントを書くのでもいい、なんでも好きにやりましょう。