Edited at

たった6個のsedを通せば、Apacheログは驚くほど扱いやすくなる

More than 1 year has passed since last update.


Q. awk '{print $9}'とかでUser-Agent丸ごと取り出したい

とか思ったことない? Apacheのログ解析で。でもできないじゃない。例えば


combined形式ログ

192.168.0.1 - - [17/Apr/2014:11:22:33 +0900] "GET /index.html HTTP/1.1" 200 43206 "https://www.google.co.jp/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36"


なんかのログで"mozilla/5.0 (Windows NT 6.1 …… Safari/537.36"の部分が欲しいなーと思って、AWKで取ろうとしても


こーなってしまう

$ awk '{print $12}' httpd-access.log

"Mozilla/5.0
$

なーんてふうに、最初のスペースまでで切れてしまって全然使い物にならない。さて、何とかならないものか。


A. 6個のsedコマンドにパイプで通せばできるよ

でも、そこは我らがUNIX。シェルスクリプトとパイプと標準コマンドさえあればお手のもの。sedコマンド6個通すだけでできるようになるのさ。

次のシェルスクリプトを書いてこいつに流し込むだけ。

(2014/05/05) おい、動かねーじゃねーか!という指摘を受けて修正しました。m(_ _;)m


apalognorm.sh(Apachログを整形するシェルスクリプト)

#! /bin/sh

# ----- ちょいと下ごしらえ -----
RS=$(printf '\036') # 元々の改行位置にマークするための記号定義
LF=$(printf '\\\n_');LF=${LF%_} # sedで改行コードを挿れるための定義

# ----- 本番 -----
sed 's/^\(.*\)$/\1'"$RS"'/' |
sed 's/"\([^"]*\)"/'"$LF"'"\1"'"$LF"'/g' |
sed 's/\[\([^]]*\)\]/'"$LF"'[\1]'"$LF"'/g' |
sed '/^["[]/s/[[:blank:]]/_/g' | # ここに空白の代替文字
sed 'N;$s/\n//g' |
sed 's/'"$RS"'/'"$LF"'/g'


試しに実行してみると、


ほらこのとおり

$ cat httpd-access.log | apalognorm.sh

192.168.0.1 - - [17/Apr/2014:11:22:33_+0900] "GET_/index.html_HTTP/1.1" 200 43206 "https://www.google.co.jp/" "Mozilla/5.0_(Windows_NT_6.1;_WOW64)_AppleWebKit/537.36_(KHTML,_like_Gecko)_Chrome/34.0.1847.116_Safari/537.36"
$

日時列(4列目)、HTTPリクエストパラメーター列(5列目)、User-Agent列(9列目)に含まれているスペースが全て_に置換されている。もちろん、列を区切っているスペースはそのままで。

もし、_が気に食わないのであれば*でも+でも、好きな文字列(2文字以上でもいい)を4番目のsedの後半部分に書けばいいだけ。


6つのsedは何をやってるのか?


sed 1号

(加工の都合により、途中で一時的に改行を挿むので)元の改行を別の文字(0x1e)で退避させておく。


sed 2号

ダブルクォーテーションで囲まれている区間"~"があったら、その前後に改行を挿み、その区間を単独の行にする。


sed 3号

ブラケットで囲まれいる区間[~]も同様に、前後に改行を挿んで、この区間を単独の行にする。


sed 4号

ダブルクォーテーション、またはブラケットで始まる行は、先程行を独立させた区間なので、これらの行にある空白をそうでない文字列に置換する。


sed 5号

改行を全部取り除く。(これはべつにsedでやる必要ないのだけど)


sed 6号

退避させていた元々の改行を復活させる。(これもべつにsedでやる必要ないのだけど)


コマンド化したものをGitHubに置いておいたよ

例によってちゃんとコマンド化したものをGistに上げておいた。ログ解析で困っているなら使ってみてね。スペースの代替文字が_では気に入らない人向けに、オプションで指定できるよにしてある本格派だ。

Apacheサーバー管理者は、これで少し幸せになれるかも。

尚、Gistに上げたものは、5号と6号のsedはtrに置き換えているので悪しからず。まぁ、全部sedでやるというのはネタだからねぇ。