🐄

Apacheのアクセスログを時間指定して、特定のステータスコードログを取得するコマンド

2022/07/27に公開

はじめに

の、記事はあります。それを自前用に調整する上で解説いれました。

https://qiita.com/junki20158/items/c3b4c3b1d093553d8656

ログ出力の形式を把握する

サンプルのaccess_logがこちらです。

IP.IP.IP.IP - - [27/Jul/2022:12:34:56 +0900] "GET /css/yes.iam.css HTTP/2.0" ...

意外と日付周りがくっついてることが分かります。これを引っぺがすために上で紹介したQiitaではsedでカットしています。

sed -r 's/(:[0-9]{4,5}|\/202[0-9]:)/ /' /PATH/logs/access_log

正規表現をONにして『s/置換前/置換後/』で置換しています。
内容は、「:」スタートで数字が4-5個並んでいるかまたは、「/」スタートで2020-2029で「:」で終わってるものは空白にします。

これをすることで

IP.IP.IP.IP - - [27/Jul 12:34:56 +0900] "GET /css/no.imnot.css HTTP/2.0" ...

こうなって、時間帯が空白で挟まれます。こうなるとawkの独壇場です。

何時からログが欲しいんや

上で紹介したQiitaではreadコマンドです。これはCUIで時刻を入力する形式です。
私は今回定期バッチでやりますので、変数を別のプログラムで入力します。その場合コマンドではこんな感じに頭にベタ書きで宣言します。

sTrttim="11:00:00" ; sed -r 's/(:[0-9]{4,5}|\/202[0-9]:)/ /' /PATH/logs/access_log

ただただ先ほどのsedの前に時間を変数に入れただけで出力内容はこの時点で変わりません。この冒頭の記述は

# echo $sTrttim
11:00:00
# sTrttim="10:00:00" ; echo $sTrttim
10:00:00

こんな感じで変数にいれて、呼び出せますし、再利用もできます。

あとは全部やってくれる。awkならね。

awkコマンドで、プログラムを書きます。さきほどの変数sTrttimとたった今の時刻(dateコマンド)をawk用に値を渡します。

awk -va=$sTrttim -vb=`date +%H:%M:%S` '{ if( $5>a && $5<b && $10>=200 && $10<=599 ) print $5, $10 }'

で、$5は半角区切りで5番目の値です。$10は10番目。このためにsedで時刻を 両脇半角スペース にした訳ですね。これがログ的にどの箇所かというと『print $5, $10』で出力します。

# sTrttim="11:00:00" ; sed -r 's/(:[0-9]{4,5}|\/202[0-9]:)/ /' /PATH/logs/access_log | awk -va=$sTrttim -vb=`date +%H:%M:%S` '{ if( $5>a && $5<b && $10>=200 && $10<=599 ) print $5, $10 }'
11:15:47 200
11:15:48 404
11:15:53 200
11:15:54 404
11:15:54 200
11:15:54 200
11:15:54 200
11:16:01 200
11:16:02 404
11:16:05 200
11:16:05 404
11:16:11 200
11:16:11 404

はい。時刻と、HTTPステータスコードです。これをIF文で欲しい情報に絞っています。

  • 指定した時間から現在まで
  • 200-599のステータスコード

これを『sTrttim="11:16:00"』とかにすると 11:16 以降のログしか拾ってきません。

全部ログを出す場合は『print $0』で出せます。あとあなたは必要に応じてemailやLINE、Slackに送信します。

ちなみに

エラーログの場合も

[Wed Jul 27 11:16:11.343131 2022] [proxy_fcgi:error]...

マイクロ秒とる出力形式だったので、そこに引っ掛けまして...

sTrttim="11:16:00" ; sed -r 's/(\.[0-9]{6})/ /' /PATH/logs/error_log | awk -va=$sTrttim -vb=`date +%H:%M:%S` '{ if( $4>a && $4<b ) print $0 }'

こんな感じで拾えました。ワードを絞りたい場合は、間にパイプでgrepなり差し込みます。

...error_log | grep -e 'Fatal Error' -e 'Parse error' -e 'PHP Warning' | awk...

Discussion