LTSVログをパースする最強のワンライナー集
最初に結論
これ最強cat accesslog | perl -F'\t' -nale '%h=map{split/:/,$_,2}@F;print"$h{time}\t$h{ua}"'
なぜPerlワンライナーなのか?
LTSVログを解析するには、Perlのワンライナーに限る。なぜならPerlはほとんどのサーバにデフォルトで入ってるから。
Perl 5.8で動くワンライナーを覚えておけばどの環境でも使える。
「何にも依存しない」
これ最強。
基本中のキホン
まずは基本形です。これだけは絶対覚えてしまいましょう。
perl -nale 'print'
% cat access_log | perl -nale 'print '
time:[22/Feb/2014:15:13:07 +0900] host:10.10.200.102 ident:- user:- method:GET path:/css/user.css query:?20130919 proto:HTTP/1.1 status:200 size:14164 referer:https://example.com/home ua:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko taken:199
これは何もしないフィルタで、ただ cat してるのと同じことです。しかし、これさえ覚えれば勝ちです。
え?右側の -nale 'print'が覚えられないって?
「ネイルプリント」とでも覚えておきましょう。
こんな感じで。
ネイルプリント
タブ区切りを配列として格納
perl -F'\t' -nale 'print @F'
出力はさっきとほぼ同じです。
% cat access_log | perl -F'\t' -nale 'print @F'
time:[22/Feb/2014:15:13:07 +0900]host:10.10.200.102ident:-user:-method:GETpath:/css/user.cssquery:?20130919proto:HTTP/1.1status:200size:14164referer:https://example.com/homeua:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Geckotaken:199
time:[22/Feb/2014:15:13:07 +0900]host:10.10.200.102ident:-user:-method:GETpath:/images/user.gifquery:proto:HTTP/1.1status:200size:577referer:https://example.com/homeua:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Geckotaken:145
ここまでだとあまり実用性はないです。面白いのはここからだ・・・!!
行列の縦横変換
だんだん実用的になってきます。perl -F'\t' -nale 'print for @F'
% cat access_log | perl -F'\t' -nale 'print for @F'
time:[22/Feb/2014:15:13:07 +0900]
host:10.10.200.102
ident:-
user:-
method:GET
path:/css/user.css
query:?20130919
proto:HTTP/1.1
status:200
size:14164
referer:https://example.com/home
ua:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
taken:199
time:[22/Feb/2014:15:13:07 +0900]
host:10.10.200.102
ident:-
user:-
method:GET
path:/images/user.gif
だいぶ見やすくなりました。でも1リクエストごとの切れ目がないのでちょっと見にくいですね。
区切りを入れてみましょう。
1リクエストごとに空行を入れる
perl -F'\t' -nale 'print for @F;print ""'
% cat access_log | perl -F'\t' -nale 'print for @F;print ""'
time:[22/Feb/2014:15:13:07 +0900]
host:10.10.200.102
ident:-
user:-
method:GET
path:/css/user.css
query:?20130919
proto:HTTP/1.1
status:200
size:14164
referer:https://example.com/home
ua:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
taken:199
time:[22/Feb/2014:15:13:07 +0900]
host:10.10.200.102
ident:-
user:-
だいぶ見やすくなりました!急いでるときはこんなんでも十分でしょう。
行をハッシュに変換する
LTSVのメリットはハッシュと相性がよいことです。PerlでLTSVの行をハッシュに変換するには次のようにします。
perl -F'\t' -nale '%h=map{split/:/,$_,2}@F;print"$h{time}\t$h{ua}"'
% cat access_log | perl -F'\t' -nale '%h=map{split/:/,$_,2}@F;print"$h{time}\t$h{ua}"'
[22/Feb/2014:15:13:07 +0900] Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
[22/Feb/2014:15:13:07 +0900] Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
[22/Feb/2014:15:13:07 +0900] Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
見やすい!Data::Dumperモジュールを使ってハッシュを丸ごと表示してみるのもよいでしょう。
perl -MData::Dumper -F'\t' -nale '%h=map{split/:/,$_,2}@F;print Dumper \%h'
cat access_log | perl -MData::Dumper -F'\t' -nale '%h=map{split/:/,$_,2}@F;print Dumper \%h'
$VAR1 = {
'ua' => 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko',
'proto' => 'HTTP/1.1',
'status' => '200',
'query' => '',
'time' => '[22/Feb/2014:15:13:07 +0900]',
'path' => '/images/user.gif',
'ident' => '-',
'size' => '149',
'host' => '10.10.200.102',
'taken' => '127',
'user' => '-',
'method' => 'GET',
'referer' => 'https://example.com/home'
};
$VAR1 = {
'ua' => 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko',
'proto' => 'HTTP/1.1',
べんり!
おまけ:ログファイルは必ずパイプで渡す
さてここまで読んで、「わざわざ左でcatコマンド起動するの馬鹿じゃね?」と思われたかもしれません。その通りです。catするぐらいなら、ファイル名を右に書く、つまり標準引数や入力リダイレクトを使う方が、速度は速いでしょう。
perl -nale 'print' access_log
または
perl -nale 'print' < access_log
しかし左側にcatをわざと書いたのには理由があります。
cat access_log | perl ...
この形を覚えておけば、catのかわりにtail,head,grepなどを使うときに楽なのです。
# リアルタイム表示
tailf accesslog | perl ...
# 行絞り込み
grep path:/images/ accesslog | perl ...
# gz圧縮されたログを展開
gunzip -c access_log.1.gz | perl ...
# 複数の圧縮ログを展開
gunzip -c access_log.*.gz | perl ...
それではHappy parsing!