CloudWatch Logs InsightsでApacheログのステータスコードを集計する

  • AWS
  • CloudWatch
  • Logs Insights

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

ApacheログをCloudWatch Logs Insightsでパースして、ステータスコード別に集計するクエリ。

パース部分

Apacheのcombinedログ形式(%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-agent}i")を想定したパターン。

parse '* - * [*] "* * *" * * "*" "*"' as host, identity, dateTimeString, httpVerb, url, protocol, statusCode, bytes, Referer, UserAgent

RefererとUserAgentはログ上ダブルクォートで囲まれているので、パターン側も"*"で囲む。ここを素の*にすると、ワイルドカードの数とas以降のフィールド数が合わなくなる。

X-Forwarded-For相当のClientIpまで取りたい場合はこう。

parse '* - * [*] "* * *" * * "*" "*" "*"' as host, identity, dateTimeString, httpVerb, url, protocol, statusCode, bytes, Referer, UserAgent, ClientIp

2xxの件数を数える

parse '* - * [*] "* * *" * * "*" "*"' as host, identity, dateTimeString, httpVerb, url, protocol, statusCode, bytes, Referer, UserAgent
| filter statusCode like /^2\d\d$/
| stats count() as count

count()は単体では使えなくて、必ずstats経由で呼ぶ必要がある。statsを付け忘れるとエラーになる。

正規表現は前後を^ $で挟んでアンカーしておく。囲まないと意図しない部分一致を拾う可能性がある。

2xxの一覧を見る(期間指定・件数は数えない)

parse '* - * [*] "* * *" * * "*" "*"' as host, identity, dateTimeString, httpVerb, url, protocol, statusCode, bytes, Referer, UserAgent
| filter statusCode like /^2\d\d$/

期間はクエリの時間範囲指定で絞る。集計しないのでソートしたい場合は自動フィールドの@timestampを使うほうが確実(パースしたdateTimeStringは文字列としてのソートになり、CLF形式の月が英字略称だと辞書順と実際の時系列順が一致しないことがある)。

| sort @timestamp desc

urlごとに4xxの件数を数える

parse '* - * [*] "* * *" * * "*" "*" "*"' as host, identity, dateTimeString, httpVerb, url, protocol, statusCode, bytes, Referer, UserAgent, ClientIp
| filter statusCode like /^4\d\d$/
| stats count() as count by url
| sort count desc

by urlを付けると自動的にurlごとのグループ集計になる。上位から見たいのでcount descでソート。