やりたいこと
Apache のアクセスログを CloudWatch Logs Insights を使ってステータスコード毎に集計する。
前提
Apache のアクセスログは次の通り、CloudWatch ログに記録されているものとする。
127.0.0.1 - - [14/May/2024:12:57:09 +0000] "GET / HTTP/1.1" 200 5 "-" "curl/8.3.0"
Apache のアクセスログログを CloudWatch ログに吐き出す方法については本題ではないため、以下のページを参考にさせていただきました。
CloudWatch Logs Insights で集計する
クエリ構文については以下のページを参考にさせてもらいました。
結論
結果としては以下のクエリとなりました。
parse '* - * [*] "* * *" * * * *' as host, identity, dateTimeString, httpVerb, url, protocol, statusCode, bytes,Referer,UserAgent
| stats count() as count_status by statusCode
| sort statusCode asc
ここで 上からクエリの詳細を確認していきます。
parse
一時フィールドとしてデータを抜き出しています。
例えば、parse の 1行目だけを実行した結果は以下の通りです。
stats
statusCode 毎に count 関数を使って集計しています。
sort
statusCode を昇順にしています。
SQLでいう ORDER BY
です。
boto3
これではつまらないので boto3 で実装してみた。
import boto3
import time
# クライアントの作成
logs_client = boto3.client('logs')
# クエリの設定
log_group_name = 'access_log' # ロググループの名前を指定
query_string = '''
parse '* - * [*] "* * *" * * * *' as host, identity, dateTimeString, httpVerb, url, protocol, statusCode, bytes,Referer,UserAgent
| stats count() as count_status by statusCode
| sort statusCode asc
'''
# クエリの開始
response = logs_client.start_query(
logGroupName=log_group_name,
startTime=int((time.time() - 3600) * 1000), # 過去1時間のログを対象とする場合
endTime=int(time.time() * 1000), # 現在時刻
queryString=query_string,
limit=1000
)
query_id = response['queryId']
# クエリの結果を取得
while True:
response = logs_client.get_query_results(
queryId=query_id
)
if response['status'] == 'Complete':
break
print('Waiting for query to complete...')
time.sleep(1) # 1秒待機してから再度チェック
# クエリ結果の出力
for result in response['results']:
print(result)
結果は以下の通りです。
[{'field': 'statusCode', 'value': '200'}, {'field': 'count_status', 'value': '8'}]
[{'field': 'statusCode', 'value': '404'}, {'field': 'count_status', 'value': '1'}]