これは何?
AWS S3のアクセスログをAthenaで集計するまでの手順のメモです。
手順
ログ保存用バケット作成
以下の名前で作成:
- 名前:
example-access-logs
ログ配信グループ(ACL)を許可するポリシーの設定
S3ログ配信グループ ACLを許可する設定を行う。
example-access-logs バケットのポリシーに以下を設定。
example-main-bucket が集計対象のバケット。
"StringEquals": { "aws:SourceAccount": "123456789012" } にはアカウントIDを設定。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3ServerAccessLogsPolicy",
"Effect": "Allow",
"Principal": {
"Service": "logging.s3.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::example-access-logs/*",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "123456789012"
},
"ArnLike": {
"aws:SourceArn": "arn:aws:s3:::example-main-bucket"
}
}
}
]
}
アクセスログの有効化
example-main-bucket の設定で「サーバーアクセスのログ記録」を有効化。
設定例:
-
送信先バケット:
s3://example-access-logs -
ログオブジェクトキー形式:
123456789012/ap-northeast-1/example-main-bucket/[YYYY]/[MM]/[DD]/[YYYY]-[MM]-[DD]-[hh]-[mm]-[ss]-[UniqueString] - ここは好きな形式で設定できる。ファイルが増えたとき、日付などでパーティションを区切る方が集計しやすそうなので上記形式とした
- ログオブジェクトキーの形式で使用される日付のソース
- S3 イベントの時刻で設定
設定後, 15分くらいしたらアクセルログファイルが作成され始めた。
Athenaで集計
参考: AWS公式ドキュメント
データベース作成
CREATE DATABASE s3_access_logs_db;
これで作成できるはずだが、以下のエラーが出た。
No output location provided. An output location is required either through the Workgroup result configuration setting or as an API input.
クエリ結果出力先のs3が必要らしいので、バケット aws-athena-query-results-ap-northeast-1-12345678 を作成し、保存先とする。
※バケット名は適当な名前でOK
athena → クエリエディタ → 設定 → 管理 から保存先バケットを設定可能。
もう一度クエリを実行したところ、DBを作成できた。
Athenaテーブル作成
クエリ実行し、集計用テーブル example_bucket_logs を作成
CREATE EXTERNAL TABLE s3_access_logs_db.example_bucket_logs(
`bucketowner` STRING,
`bucket_name` STRING,
`requestdatetime` STRING,
`remoteip` STRING,
`requester` STRING,
`requestid` STRING,
`operation` STRING,
`key` STRING,
`request_uri` STRING,
`httpstatus` STRING,
`errorcode` STRING,
`bytessent` BIGINT,
`objectsize` BIGINT,
`totaltime` STRING,
`turnaroundtime` STRING,
`referrer` STRING,
`useragent` STRING,
`versionid` STRING,
`hostid` STRING,
`sigv` STRING,
`ciphersuite` STRING,
`authtype` STRING,
`endpoint` STRING,
`tlsversion` STRING,
`accesspointarn` STRING,
`aclrequired` STRING)
PARTITIONED BY (`timestamp` string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
'input.regex'='([^ ]*) ([^ ]*) \\[(.*?)\\] ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) (-|[0-9]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) ([^ ]*)(?: ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*))?.*$')
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION 's3://example-access-logs/123456789012/ap-northeast-1/example-main-bucket/'
TBLPROPERTIES (
'projection.enabled'='true',
'projection.timestamp.format'='yyyy/MM/dd',
'projection.timestamp.interval'='1',
'projection.timestamp.interval.unit'='DAYS',
'projection.timestamp.range'='2024/01/01,NOW',
'projection.timestamp.type'='date',
'storage.location.template'='s3://example-access-logs/123456789012/ap-northeast-1/example-main-bucket/${timestamp}')
以下を環境に合わせて修正してください。
| 修正箇所 | 意味・修正方法 | 例 |
|---|---|---|
s3_access_logs_db |
Athenaのデータベース名。自分の環境で作成したDB名に変更する |
CREATE DATABASE my_s3_logs; → my_s3_logs.example_bucket_logs
|
example_bucket_logs |
作成するテーブル名。任意で変更可能(プロジェクト名などに合わせる) | my_access_logs |
LOCATION |
ログを保存しているS3バケットのパス。 アクセスログを出力した「保存先バケット」に合わせる |
s3://my-access-logs/111122223333/ap-northeast-1/my-source-bucket/ |
'storage.location.template' |
上記LOCATIONと対応させる。パス構造(日付階層)が違う場合は修正が必要 | s3://my-access-logs/111122223333/ap-northeast-1/my-source-bucket/${timestamp} |
"projection.timestamp.range" |
ログの保管開始時期に合わせて適宜修正 |
'2023/01/01,NOW' など |
"ap-northeast-1" |
ログを保存しているリージョンに変更 |
us-east-1, eu-west-1 など |
"123456789012" |
自分のAWSアカウントIDに置き換える | (例)463737866732
|
'input.regex' |
S3アクセスログ形式に基づく正規表現。基本的に変更不要だが、フォーマットを変えている場合は要調整 | 通常はそのままでOK |
PV集計クエリ
Athenaのクエリエディタで以下を実行する
SELECT
regexp_extract(key, '^([^/]+)/', 1) AS user_id,
COUNT(*) AS pv_count
FROM s3_access_logs_db.example_bucket_logs
WHERE
operation = 'REST.GET.OBJECT'
AND httpstatus = '200'
GROUP BY regexp_extract(key, '^([^/]+)/', 1)
ORDER BY pv_count DESC;
日付別集計例
SELECT
regexp_extract(key, '^([^/]+)/', 1) AS user_id,
timestamp AS log_date,
COUNT(*) AS pv_count
FROM s3_access_logs_db.example_bucket_logs
WHERE
operation = 'REST.GET.OBJECT'
AND httpstatus = '200'
AND timestamp BETWEEN '2025/05/01' AND '2025/05/31'
AND regexp_extract(key, '^([^/]+)/', 1) = '13'
GROUP BY regexp_extract(key, '^([^/]+)/', 1), timestamp
ORDER BY timestamp, pv_count DESC;
WHEREにユーザーIDを指定したり、日付範囲を指定したりすれば、自由に集計できそう。
コストについて
Athenaはスキャン量に応じて課金。
2025年現在、$5 / TB
- 1回のクエリ実行で、最低でも10MBスキャン分の料金がかかる
- WHERE句で範囲を絞るとコスト削減可能
- 正常終了しなかったクエリには課金されない
- 日付ごとのパーティション設計で効率化できる
まとめ
S3サーバーアクセスログをAthenaで可視化することで、どのオブジェクトがどれだけアクセスされたかを簡単に集計可能です。定期的に分析する場合は、クエリを自動実行するLambdaなども検討するとよさそうです。