【AWK】アクセスログから404を返したURLを抽出する

AWKを使って、アクセスログから404を返したページのパスを取得する方法を紹介します。定期的な監視はLogwatchなどを使った方がいいと思われますが、AWKを使った方法を知っておくと、さっと調べたいときに便利です。

今回使うのはNginxのアクセスログですが、アクセスログのフォーマットを確認すれば、他のWebサーバ(Apacheなど)にも応用できると思われます。

アクセスログのフォーマットを確認

AWKの入力にアクセスログを使うので、まずはアクセスログの確認をします。例として、以下の形式でアクセスログが出力されていたとします。

xxx.xxx.xxx.xxx - - [03/Aug/2015:xx:xx:xx +0900] "GET /blog/1397/ HTTP/1.1" 200 9518 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko)" "-"

ここで重要なのが以下の3点です。これら情報はAWKで使います。

  • 各項目がスペースで区切られている。
  • URLのパスが7カラム目に出力されている。
  • HTTPステータスコードが9カラム目に出力されている。

AWKで404を抽出

AWKを使ってアクセスログの特定の行を抽出し、特定のカラムを出力します。なお、AWKの簡単な使用方法については昔書いた記事が参考になれば幸いです。

HTTPステータスコードとパスを出力

まずは、先ほど調べたアクセスログのフォーマットが正しいかを確認します。そのために、AWKを使ってHTTPステータスコードとパスを出力してみます。

HTTPステータスコードとパスはそれぞれ、スペースで区切られたアクセスログの7カラム目と9カラム目だったので、以下のようにして画面に出力することができます。ちなみに、最後に付けた| sort | uniqは、ソートしてから重複を省いています。

# HTTPステータスコードを重複なしで出力します。
$ cat /path/to/access.log | awk 'BEGIN { FS = " "; } { print $9; }' | sort | uniq
200
...
404
...

# アクセスがあったURLのパスを重複なしで出力します。
$ cat /path/to/access.log | awk 'BEGIN { FS = " "; } { print $7; }' | sort | uniq
/blog/107/
/blog/1151/
...

上記コマンドのBEGIN { FS = " "; }は、各カラムの区切り文字を定義しています。ちなみに、FSはデフォルトでスペースを区切り文字として認識してくれるため、FSの定義は省略できます。以降、この記事ではFSの定義を省略します。

上記コマンドを打って、HTTPステータスコードとURLのパスが出力されていることを確認したら、次に進みます。

HTTPステータスコードが404の行を絞り込み

HTTPステータスコードとURLのパスのカラムが正しいことを確認したら、HTTPステータスコードが404の行を絞り込みます。HTTPステータスコードは9カラム目だったので、if ($9 == 404)のようにして絞り込めます。そして、出力するのは7カラム目のURLのパスなので、以下のコマンドになります。

$ cat /path/to/access.log | awk '{ if ($9 == 404) print $7; }'
/blog/181/
/blog/163/
...

これで、アクセスログから404を返したページのパスを抽出できました!ただ、このままだと見づらいので整形します。

uniq、sortコマンドで整形

AWKの結果を、uniqコマンドとsortコマンドで整形します。整形内容は以下の3点です。

  • 重複が省かれている。
  • 404を返した回数も表示されている。
  • 404を返した回数の多い順にソートされている。

それを実現するためのコマンドは、以下のようになります。

$ AWKの結果 | sort | uniq -c | sort -r

sort | uniqでAWKの結果から重複を省いています。また、uniq -cで重複した回数も出力しています。この段階では以下のように、出現回数 URLのパスとなっています。

2 /blog/foo/
4 /blog/bar/
...

sort -rsort | uniq -cした結果を降順に並べ替えています。なお、sortコマンドの区切りのデフォルトは空白なので、出現回数の降順URLのパスの降順でソートされます。

まとめ

以上をまとめて、AWKを使ってアクセスログから、404を返したページのパスを取得するのは以下のコマンドになります。(※ページのパスがアクセスログの7カラム目、HTTPステータスコードが9カラム目に出力されている場合です。)

$ cat /path/to/access.log | awk '{ if ($9 == 404) print $7; }' | sort | uniq -c | sort -r

おまけ

gzipで圧縮されたファイルを対象にする場合

logrotateなどで、調査対象のアクセスログがgzipで圧縮されているケースもあるかと思われます。その場合は、catの代わりにzcatを使うとファイルを解凍しないで調査できます。

$ zcat /path/to/access.log.gz | awk '{ if ($9 == 404) print $7; }' | sort | uniq -c | sort -r

この記事が役に立った場合、シェアしていただけると励みになります!!