SOMPO Digital Lab ソフトウェアエンジニアの木村です。
数日前にAthenaでALBのアクセスログを解析しようとしたときに、 データが空になってしまっていることに気が付きました。
今回はその不具合を解決した時の作業ログから記事を起こしました
原因
原因はALBアクセスログに新規カラムconne_trace_id
が追加されたことによるものでした。
私のプロダクトではAWS GlueとAthenaを統合して利用しているのですが、 カラムが追加されたことによりAWS Glueのカタログテーブルのパラメータ定義とALBアクセスログのフォーマットに差異が生じていました。そのため、S3に保存したログデータが読み込めなくなってしまっていました。
ログのカラム追加については、現時点では英語版のAthenaドキュメントにのみ記載があり、以下のように書いてあります。
The following CREATE TABLE statement includes the recently added classification, classification_reason, and conn_trace_id columns. To create a table for Application Load Balancer access logs that do not contain these entries, remove the corresponding columns from the CREATE TABLE statement and modify the regular expression accordingly.
どうやら最近 conn_trace_id
カラムが追加されたらしいです(classification, classification_reason
については既に対応済みでした)。
解決方法
AWSのドキュメントにも記載のあるように、input.regex
を変更してあげると解決します。
CREATE EXTERNAL TABLE IF NOT EXISTS alb_access_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 int, 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, target_port_list string, target_status_code_list string, classification string, classification_reason string, conn_trace_id 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]*) ([^ ]*) \"([^\"]*)\" \"([^\"]*)\" \"([^ ]*)\" \"([^\s]+?)\" \"([^\s]+)\" \"([^ ]*)\" \"([^ ]*)\" ?([^ ]*)?( .*)?') LOCATION 's3://DOC-EXAMPLE-BUCKET/access-log-folder-path/'
上記はSQLで書かれていますが、私のプロダクトの場合はAWS GlueのカタログテーブルをTerraformで定義しているため読み換えて以下のようにします。
resource "aws_glue_catalog_table" "my_product_alb_access_log" { name = "my_product_alb_access_log" (略) storage_descriptor { location = "s3://[バケット名]/AWSLogs/[アカウントID]/elasticloadbalancing/ap-northeast-1" input_format = "org.apache.hadoop.mapred.TextInputFormat" output_format = "org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat" ser_de_info { serialization_library = "org.apache.hadoop.hive.serde2.RegexSerDe" parameters = { "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]*) ([^ ]*) \"([^\"]*)\" \"([^\"]*)\" \"([^ ]*)\" \"([^s]+?)\" \"([^s]+)\" \"([^ ]*)\" \"([^ ]*)\" ?([^ ]*)?( .*)?" } columns = { name = "type" type = "string" } (略) columns { name = "conn_trace_id" type = "string" } columns { name = "extra_column" type = "string" } } }
ポイントはinput.regex
の正規表現の末尾の部分とextra_column
の部分です。
conn_trace_id
以降のカラムを正規表現( .*)?
を使ってextra_column
としてキャプチャすることで、
今後同じように予期しないカラムが追加されたとしてもフォーマットの差異によりログが解析できなくなるということはなくなるはずです。
conn_trace_id とはなんなのか
traceability_id
と言われるものらしいです。
アクセスログ以外にも接続ログにも同様の値が追加されており、 このカラムを付き合わせることでアクセスログと接続ログの突き合わせが簡単になるとのことです。
詳細はクラスメソッドさんの記事を参照してください。
まとめ
ログを分析しようとしてデータが何も出てこなくなったときは「ログが消えている」と思って肝が冷えました。
ALBアクセスログをAthenaで分析する場合は、いきなりカラムが追加されることを想定した作りにしておかなければならないようです。
SOMPO Digital Labでは一緒に働くソフトウェアエンジニアを募集しています
SOMPO Digital Labでは高速でログ分析を行いプロダクトをエンハンスするエンジニアを募集しています。
以下のリンクからカジュアル面談の応募ができますので、興味を持った方は是非話を聞きに来て下さい