自動化無しに生活無し

WEB開発関係を中心に備忘録をまとめています

Nginxのログをawkコマンドを使用して調べる【crontabで特定の条件下のログを管理者へ報告】

thumbnail

Nginxのログはスペース区切りで送信元IPアドレス、アクセス対象のURLなどが書かれてある。これはスペース区切りで文字を扱うことができるawkコマンドと相性が良い。

本記事では、awkコマンドを使用して、特定の条件下のログを報告したり、ログの情報を見やすくさせる方法を記す。

awkコマンドを使用して、表示する情報を絞る

基本。

cat access.log | awk '{print $1}'

これで送信元IPアドレス(スペース区切りで1番目のデータ)が表示される。

【応用1】IPアドレスごとにリクエスト数を計算して表示

sortコマンドとuniqコマンドを使用する。これはワンライナーで簡単に書ける。

cat access.log | awk '{print $1}' | sort | uniq -c | sort -rn 

【応用2】HTTPレスポンスごとに発生回数を調べる

先ほどと同様。$9がHTTPレスポンスなのでsortしてuniqする。

cat access.log | awk '{print $9}' | sort | uniq -c | sort -rn 

【応用3】アクセスの多いページ順に表示

これも同様。$11を指定するだけ

cat access.log | awk '{print $11}' | sort | uniq -c | sort -rn 

【応用4】管理サイトにアクセスしたIPアドレスの中から管理者のものと不一致であれば報告

シェルスクリプトで書く。awk内のif文はshellscriptの構文とは違う点に注意。

管理者のIPアドレスではないものが、管理サイトのURLにアクセスしたとき、データを配列に格納する。

#配列を作る
declare -a doubt=()

#条件に一致したデータを配列に入れる
mapfile -t doubt <<< $( awk '{
if ($1 != "管理者のIPアドレス" && $11 ~ /管理サイトのURL/) 
    print $1" "$11
}' <<< cat access.log )

#配列の長さが0以上であれば報告
if [ ${#doubt[@]} -gt 0 ]; then
    echo "管理者へ通知"
fi

一旦、配列として受け取り、長さを測る。0よりも多ければ管理者へ通知の処理を書く。問題ありの$doubtをセットで送るもよし。

print $1" "$11で送信元IPアドレスとURLを記録しているので、時間も入れると良いだろう。

【応用5】1分以内に一定回数以上のリクエストを送ったIPアドレスを表示

下記シェルスクリプトをcrontabで毎分実行する。

target=`date -d '1 minute ago' +'%Y:%H:%M'`
echo $target
grep $target ./access.log | awk '{print $1}' | sort | uniq -c | sort -rn 
declare -a requests=()
mapfile -t requests <<< $( grep $target access.log | awk '{print $1}' | sort | uniq -c | sort -rn | awk '{
if ($1 >= 100 )
    print $2
}')

#ここはif文で配列の長さが0以上であればメールで通知する。
echo ${requests[@]} "は1分間に100回以上のアクセスがある。"

こんなふうになる。

dateとgrepと組み合わせることで、予め(分単位で)現在時刻と同じログを抽出。後はソートして重複除去、awkのif文で回数を超過したものを配列に追加。

配列に含まれているデータを通知する。

分をまたいだアクセスには対応できないが、毎分crontabで実行すればある程度の効果はあると思われる。Nginxのログは1つのファイルに1日以上(24時間以上)のデータが含まれることは無いので、日は気にしなくて良い。

ログを取得する期間を引き伸ばしたいなど、ログの設定を行いたい場合は下記

Nginxのログをチェックする、ログの出力設定を変更する

特定IPアドレスの拒否がしたい場合は下記。

Nginxで特定IPアドレスのリクエストを拒否する

スポンサーリンク