Carpe Diem

備忘録

ALBのアクセスログをAthenaで分析

概要

AthenaでALBのアクセスログの分析が非常に簡単にできるので、設定方法とよく使うクエリを紹介します。

手順

ALBアクセスログをS3に保存

新規バケットを同時に作成する場合

バケットポリシーが自動で設定されるので楽なやり方です。
ELBの属性の編集でチェックボックスをONにします。

f:id:quoll00:20190209072232p:plain

このときにS3バケットの作成を一緒にやります。

既存のS3を使いたい場合

既存のS3バケットを保存先にしたい場合は以下のバケットポリシーを付与します。

{
    "Version": "2012-10-17",
    "Id": "AWSConsole-AccessLogs-Policy-1549661075379",
    "Statement": [
        {
            "Sid": "AWSConsoleStmt-1549661075379",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::582318560864:root"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::<バケット名>/AWSLogs/<アカウントID>/*"
        },
        {
            "Sid": "AWSLogDeliveryWrite",
            "Effect": "Allow",
            "Principal": {
                "Service": "delivery.logs.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::<バケット名>/AWSLogs/<アカウントID>/*",
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        },
        {
            "Sid": "AWSLogDeliveryAclCheck",
            "Effect": "Allow",
            "Principal": {
                "Service": "delivery.logs.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::<バケット名>"
        }
    ]
}

この582318560864というのは東京リージョンのELBのアカウントIDです。

Application Load Balancer のアクセスログ - Elastic Load Balancing

delivery.logs.amazonaws.comにAssume Roleしてますが、こちらはフローログのための権限のようです。

AthenaにALBログのテーブルの作成

項目 設定値
テーブル名 test_alb_logs
LOCATION s3://<バケット名>/AWSLogs/<アカウントID>/elasticloadbalancing/<リージョン>/

として以下のクエリを実行します。

LOCATION

  • s3://<バケット名>/AWSLogs/<アカウントID>/elasticloadbalancing/<リージョン>/yyyy/
  • s3://<バケット名>/AWSLogs/<アカウントID>/elasticloadbalancing/<リージョン>/yyyy/MM/

まで指定可能です。ただしdd/までやるとテーブルでデータが見れませんでした。
Athenaの料金はスキャンするデータ量によって増えるので、このように分割して保存していくのも1つの手です。

また、どれも最後の/を忘れずに付けてください。

CREATE EXTERNAL TABLE IF NOT EXISTS test_alb_logs (
            type string,
            time string,
            elb string,
            client_ip string,
            client_port int,
            target_ip string,
            target_port int,
            request_processing_time double,
            target_processing_time double,
            response_processing_time double,
            elb_status_code string,
            target_status_code string,
            received_bytes bigint,
            sent_bytes bigint,
            request_verb string,
            request_url string,
            request_proto string,
            user_agent string,
            ssl_cipher string,
            ssl_protocol string,
            target_group_arn string,
            trace_id string,
            domain_name string,
            chosen_cert_arn string,
            matched_rule_priority string,
            request_creation_time string,
            actions_executed string,
            redirect_url string,
            lambda_error_reason string,
            new_field string
            )
            ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
            WITH SERDEPROPERTIES (
            'serialization.format' = '1',
            'input.regex' = 
        '([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*):([0-9]*) ([^ ]*)[:-]([0-9]*) ([-.0-9]*) ([-.0-9]*) ([-.0-9]*) (|[-0-9]*) (-|[-0-9]*) ([-0-9]*) ([-0-9]*) \"([^ ]*) ([^ ]*) (- |[^ ]*)\" \"([^\"]*)\" ([A-Z0-9-]+) ([A-Za-z0-9.-]*) ([^ ]*) \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\" ([-.0-9]*) ([^ ]*) \"([^\"]*)\" \"([^\"]*)\"($| \"[^ ]*\")(.*)')
            LOCATION 's3://<バケット名>/AWSLogs/<アカウントID>/elasticloadbalancing/<リージョン>/';

Application Load Balancer ログのクエリ - Amazon Athena

注意としてELBの種類(CLB, ALB, NLB)によってフィールドの数や種類が異なります
チュートリアルで使われるクエリもALBのものではありません。
なのでこのブログ含め、誰かのブログでなく必ず公式ドキュメントを参照してください。

動作確認

テーブル作成ができたらちゃんとデータが見れるか確認します。

f:id:quoll00:20190209073726p:plain

Preview Logsで

f:id:quoll00:20190209073913p:plain

このようになればOKです。

よく使うクエリ

ステータスコードの分布を確認

SELECT elb_status_code, count(elb_status_code) as cnt
FROM test_alb_logs
GROUP BY elb_status_code
ORDER BY cnt DESC

特定のインスタンスへのリクエストを調査

IPが10.5.20.10というインスタンスがバックエンドにあるとして、そこへのリクエストがどうなっているか確認したいとき。

SELECT * FROM test_alb_logs
WHERE target_ip = '10.5.20.10'

時間指定して調査

parse_datetimeを使ってtimeフィールドの時間帯を指定します。
以下では特定の時間帯のクライアント毎のリクエスト数を出しています。

SELECT client_ip, count(client_ip) as cnt
FROM test_alb_logs
WHERE parse_datetime(time,'yyyy-MM-dd''T''HH:mm:ss.SSSSSS''Z') 
     BETWEEN parse_datetime('2019-01-12-12:00:00','yyyy-MM-dd-HH:mm:ss') 
     AND parse_datetime('2019-01-13-00:00:00','yyyy-MM-dd-HH:mm:ss') 
GROUP BY client_ip;

latencyの高いリクエストの抽出

SELECT request_url, target_processing_time
FROM test_alb_logs
ORDER BY target_processing_time DESC
LIMIT 10;

まとめ

以前は大変だったELBのログ調査ですが、Athenaが出てきたことで簡単に分析することができるようになりました。