はじめに
以下の記事で Go で自作したアクセスログパーサーについて紹介しました。
今回はこのモジュールを使って作成した CLI ツールについて紹介します。
概要
主に以下サービスのアクセスログを扱えます。
- S3
- CloudFront
- ALB
- NLB
- CLB
変換する形式は以下に対応しています。
- NDJSON (改行区切り JSON)
- インデント付きの JSON
- key=value 形式のテキスト
ログの渡し方は以下に対応しています。ZIP の場合はデフォルトで中身のエントリをすべて対象とします。
- 文字列
- ファイル
- GZIP
- ZIP
インストール
リリースページから OS ごとのバイナリをダウンロードできます。
使い方
ヘルプです。サブコマンドがサービス名になっています。
NAME: alpen - AWS log parser/encoder USAGE: alpen [global options] command [command options] [arguments...] VERSION: 0.0.8 DESCRIPTION: A cli application for parsing AWS access logs COMMANDS: s3 Parses S3 access logs cf Parses CloudFront access logs alb Parses ALB access logs nlb Parses NLB access logs clb Parses CLB access logs GLOBAL OPTIONS: --completion value, -c value select a shell to display completion scripts: bash|zsh|pwsh --help, -h show help --version, -v print the version
s3
サブコマンドのヘルプです。他のサブコマンドもオプションは同じです。
NAME: alpen s3 - Parses S3 access logs USAGE: alpen s3 DESCRIPTION: Parses S3 access logs and converts them to structured formats OPTIONS: --input value, -i value input from string --file-path value, -f value input from file path --gzip-path value, -g value input from gzip file path --zip-path value, -z value input from zip file path --output value, -o value select output format: text|json|pretty-json (default: "json") --skip value, -s value [ --skip value, -s value ] skip records by index --metadata, -m enable metadata output (default: false) --glob-pattern value, -G value filter glob pattern: available for parsing zip only (default: "*") --help, -h show help
文字列で渡す
文字列で渡す場合は --input
, -i
を使います。なお、本記事のアクセスログはすべて AWS の公式ドキュメントに例示されているサンプルログを使用しています。
alpen s3 --input '79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be awsexamplebucket1 [06/Feb/2019:00:00:38 +0000] 192.0.2.3 79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be 3E57427F3EXAMPLE REST.GET.VERSIONING - "GET /awsexamplebucket1?versioning HTTP/1.1" 200 - 113 - 7 - "-" "S3Console/0.4" - s9lzHYrFp76ZVxRcpX9+5cjAnEH2ROuNkd2BHfIa6UkFVdtjf5mKR3/eTPFvsiP/XV/VLi31234= SigV2 ECDHE-RSA-AES128-GCM-SHA256 AuthHe ader awsexamplebucket1.s3.us-west-1.amazonaws.com TLSV1.1'
デフォルトでは NDJSON 形式で出力されます。
{"index":1,"bucket_owner":"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be","bucket":"awsexamplebucket1","time":"[06/Feb/2019:00:00:38 +0000]","remote_ip":"192.0.2.3","requester":"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be","request_id":"3E57427F3EXAMPLE","operation":"REST.GET.VERSIONING","key":"-","request_uri":"GET /awsexamplebucket1?versioning HTTP/1.1","http_status":"200","error_code":"-","bytes_sent":"113","object_size":"-","total_time":"7","turn_around_time":"-","referer":"-","user_agent":"S3Console/0.4","version_id":"-","host_id":"s9lzHYrFp76ZVxRcpX9+5cjAnEH2ROuNkd2BHfIa6UkFVdtjf5mKR3/eTPFvsiP/XV/VLi31234=","signature_version":"SigV2","cipher_suite":"ECDHE-RSA-AES128-GCM-SHA256","authentication_type":"AuthHeader","host_header":"awsexamplebucket1.s3.us-west-1.amazonaws.com","tls_version":"TLSV1.1"}
ファイルパスで渡す
ファイルパスで渡す場合は --file-path
, -f
を使います。
alpen s3 --file-path testdata/log/sample_s3.log {"index":1,"bucket_owner":"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be","bucket":"awsexamplebucket1","time":"[06/Feb/2019:00:00:38 +0000]","remote_ip":"192.0.2.3","requester":"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be","request_id":"3E57427F3EXAMPLE","operation":"REST.GET.VERSIONING","key":"-","request_uri":"GET /awsexamplebucket1?versioning HTTP/1.1","http_status":"200","error_code":"-","bytes_sent":"113","object_size":"-","total_time":"7","turn_around_time":"-","referer":"-","user_agent":"S3Console/0.4","version_id":"-","host_id":"s9lzHYrFp76ZVxRcpX9+5cjAnEH2ROuNkd2BHfIa6UkFVdtjf5mKR3/eTPFvsiP/XV/VLi31234=","signature_version":"SigV2","cipher_suite":"ECDHE-RSA-AES128-GCM-SHA256","authentication_type":"AuthHeader","host_header":"awsexamplebucket1.s3.us-west-1.amazonaws.com","tls_version":"TLSV1.1"} {"index":2,"bucket_owner":"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be","bucket":"awsexamplebucket1","time":"[06/Feb/2019:00:00:38 +0000]","remote_ip":"192.0.2.3","requester":"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be","request_id":"891CE47D2EXAMPLE","operation":"REST.GET.LOGGING_STATUS","key":"-","request_uri":"GET /awsexamplebucket1?logging HTTP/1.1","http_status":"200","error_code":"-","bytes_sent":"242","object_size":"-","total_time":"11","turn_around_time":"-","referer":"-","user_agent":"S3Console/0.4","version_id":"-","host_id":"9vKBE6vMhrNiWHZmb2L0mXOcqPGzQOI5XLnCtZNPxev+Hf+7tpT6sxDwDty4LHBUOZJG96N1234=","signature_version":"SigV2","cipher_suite":"ECDHE-RSA-AES128-GCM-SHA256","authentication_type":"AuthHeader","host_header":"awsexamplebucket1.s3.us-west-1.amazonaws.com","tls_version":"TLSV1.1"} {"index":3,"bucket_owner":"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be","bucket":"awsexamplebucket1","time":"[06/Feb/2019:00:00:38 +0000]","remote_ip":"192.0.2.3","requester":"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be","request_id":"A1206F460EXAMPLE","operation":"REST.GET.BUCKETPOLICY","key":"-","request_uri":"GET /awsexamplebucket1?policy HTTP/1.1","http_status":"404","error_code":"NoSuchBucketPolicy","bytes_sent":"297","object_size":"-","total_time":"38","turn_around_time":"-","referer":"-","user_agent":"S3Console/0.4","version_id":"-","host_id":"BNaBsXZQQDbssi6xMBdBU2sLt+Yf5kZDmeBUP35sFoKa3sLLeMC78iwEIWxs99CRUrbS4n11234=","signature_version":"SigV2","cipher_suite":"ECDHE-RSA-AES128-GCM-SHA256","authentication_type":"AuthHeader","host_header":"awsexamplebucket1.s3.us-west-1.amazonaws.com","tls_version":"TLSV1.1"} {"index":4,"bucket_owner":"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be","bucket":"awsexamplebucket1","time":"[06/Feb/2019:00:01:00 +0000]","remote_ip":"192.0.2.3","requester":"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be","request_id":"7B4A0FABBEXAMPLE","operation":"REST.GET.VERSIONING","key":"-","request_uri":"GET /awsexamplebucket1?versioning HTTP/1.1","http_status":"200","error_code":"-","bytes_sent":"113","object_size":"-","total_time":"33","turn_around_time":"-","referer":"-","user_agent":"S3Console/0.4","version_id":"-","host_id":"Ke1bUcazaN1jWuUlPJaxF64cQVpUEhoZKEG/hmy/gijN/I1DeWqDfFvnpybfEseEME/u7ME1234=","signature_version":"SigV2","cipher_suite":"ECDHE-RSA-AES128-GCM-SHA256","authentication_type":"AuthHeader","host_header":"awsexamplebucket1.s3.us-west-1.amazonaws.com","tls_version":"TLSV1.1"} {"index":5,"bucket_owner":"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be","bucket":"awsexamplebucket1","time":"[06/Feb/2019:00:01:57 +0000]","remote_ip":"192.0.2.3","requester":"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be","request_id":"DD6CC733AEXAMPLE","operation":"REST.PUT.OBJECT","key":"s3-dg.pdf","request_uri":"PUT /awsexamplebucket1/s3-dg.pdf HTTP/1.1","http_status":"200","error_code":"-","bytes_sent":"-","object_size":"4406583","total_time":"41754","turn_around_time":"28","referer":"-","user_agent":"S3Console/0.4","version_id":"-","host_id":"10S62Zv81kBW7BB6SX4XJ48o6kpcl6LPwEoizZQQxJd5qDSCTLX0TgS37kYUBKQW3+bPdrg1234=","signature_version":"SigV4","cipher_suite":"ECDHE-RSA-AES128-SHA","authentication_type":"AuthHeader","host_header":"awsexamplebucket1.s3.us-west-1.amazonaws.com","tls_version":"TLSV1.1"}
メタデータも表示する
メタデータ (簡単な集計情報とアンマッチデータの情報) も出力するには --metadata
, -m
オプションを使います。
alpen s3 --file-path testdata/log/sample_s3.log -m # 省略 {"total":5,"matched":5,"unmatched":0,"skipped":0,"source":"sample_s3.log","errors":null}
key=value 形式で表示する
出力形式は --output
, -o
で設定します。使えるのは text
, json
, pretty-json
のいずれかで、デフォルトは json
です。
text
の場合。あまり使い道はないかもしれません。
alpen s3 --file-path testdata/log/sample_s3.log -m -o text index=1 bucket_owner="79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" bucket="awsexamplebucket1" time="[06/Feb/2019:00:00:38 +0000]" remote_ip="192.0.2.3" requester="79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" request_id="3E57427F3EXAMPLE" operation="REST.GET.VERSIONING" key="-" request_uri="GET /awsexamplebucket1?versioning HTTP/1.1" http_status="200" error_code="-" bytes_sent="113" object_size="-" total_time="7" turn_around_time="-" referer="-" user_agent="S3Console/0.4" version_id="-" host_id="s9lzHYrFp76ZVxRcpX9+5cjAnEH2ROuNkd2BHfIa6UkFVdtjf5mKR3/eTPFvsiP/XV/VLi31234=" signature_version="SigV2" cipher_suite="ECDHE-RSA-AES128-GCM-SHA256" authentication_type="AuthHeader" host_header="awsexamplebucket1.s3.us-west-1.amazonaws.com" tls_version="TLSV1.1" index=2 bucket_owner="79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" bucket="awsexamplebucket1" time="[06/Feb/2019:00:00:38 +0000]" remote_ip="192.0.2.3" requester="79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" request_id="891CE47D2EXAMPLE" operation="REST.GET.LOGGING_STATUS" key="-" request_uri="GET /awsexamplebucket1?logging HTTP/1.1" http_status="200" error_code="-" bytes_sent="242" object_size="-" total_time="11" turn_around_time="-" referer="-" user_agent="S3Console/0.4" version_id="-" host_id="9vKBE6vMhrNiWHZmb2L0mXOcqPGzQOI5XLnCtZNPxev+Hf+7tpT6sxDwDty4LHBUOZJG96N1234=" signature_version="SigV2" cipher_suite="ECDHE-RSA-AES128-GCM-SHA256" authentication_type="AuthHeader" host_header="awsexamplebucket1.s3.us-west-1.amazonaws.com" tls_version="TLSV1.1" index=3 bucket_owner="79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" bucket="awsexamplebucket1" time="[06/Feb/2019:00:00:38 +0000]" remote_ip="192.0.2.3" requester="79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" request_id="A1206F460EXAMPLE" operation="REST.GET.BUCKETPOLICY" key="-" request_uri="GET /awsexamplebucket1?policy HTTP/1.1" http_status="404" error_code="NoSuchBucketPolicy" bytes_sent="297" object_size="-" total_time="38" turn_around_time="-" referer="-" user_agent="S3Console/0.4" version_id="-" host_id="BNaBsXZQQDbssi6xMBdBU2sLt+Yf5kZDmeBUP35sFoKa3sLLeMC78iwEIWxs99CRUrbS4n11234=" signature_version="SigV2" cipher_suite="ECDHE-RSA-AES128-GCM-SHA256" authentication_type="AuthHeader" host_header="awsexamplebucket1.s3.us-west-1.amazonaws.com" tls_version="TLSV1.1" index=4 bucket_owner="79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" bucket="awsexamplebucket1" time="[06/Feb/2019:00:01:00 +0000]" remote_ip="192.0.2.3" requester="79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" request_id="7B4A0FABBEXAMPLE" operation="REST.GET.VERSIONING" key="-" request_uri="GET /awsexamplebucket1?versioning HTTP/1.1" http_status="200" error_code="-" bytes_sent="113" object_size="-" total_time="33" turn_around_time="-" referer="-" user_agent="S3Console/0.4" version_id="-" host_id="Ke1bUcazaN1jWuUlPJaxF64cQVpUEhoZKEG/hmy/gijN/I1DeWqDfFvnpybfEseEME/u7ME1234=" signature_version="SigV2" cipher_suite="ECDHE-RSA-AES128-GCM-SHA256" authentication_type="AuthHeader" host_header="awsexamplebucket1.s3.us-west-1.amazonaws.com" tls_version="TLSV1.1" index=5 bucket_owner="79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" bucket="awsexamplebucket1" time="[06/Feb/2019:00:01:57 +0000]" remote_ip="192.0.2.3" requester="79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" request_id="DD6CC733AEXAMPLE" operation="REST.PUT.OBJECT" key="s3-dg.pdf" request_uri="PUT /awsexamplebucket1/s3-dg.pdf HTTP/1.1" http_status="200" error_code="-" bytes_sent="-" object_size="4406583" total_time="41754" turn_around_time="28" referer="-" user_agent="S3Console/0.4" version_id="-" host_id="10S62Zv81kBW7BB6SX4XJ48o6kpcl6LPwEoizZQQxJd5qDSCTLX0TgS37kYUBKQW3+bPdrg1234=" signature_version="SigV4" cipher_suite="ECDHE-RSA-AES128-SHA" authentication_type="AuthHeader" host_header="awsexamplebucket1.s3.us-west-1.amazonaws.com" tls_version="TLSV1.1" total=5 matched=5 unmatched=0 skipped=0 source="sample_s3.log" errors=null
インデントされた JSON で表示する
pretty-json
の場合。手元で調査する場合にいちばん実用的かと思います。
{ "index": 1, "bucket_owner": "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be", "bucket": "awsexamplebucket1", "time": "[06/Feb/2019:00:00:38 +0000]", "remote_ip": "192.0.2.3", "requester": "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be", "request_id": "3E57427F3EXAMPLE", "operation": "REST.GET.VERSIONING", "key": "-", "request_uri": "GET /awsexamplebucket1?versioning HTTP/1.1", "http_status": "200", "error_code": "-", "bytes_sent": "113", "object_size": "-", "total_time": "7", "turn_around_time": "-", "referer": "-", "user_agent": "S3Console/0.4", "version_id": "-", "host_id": "s9lzHYrFp76ZVxRcpX9+5cjAnEH2ROuNkd2BHfIa6UkFVdtjf5mKR3/eTPFvsiP/XV/VLi31234=", "signature_version": "SigV2", "cipher_suite": "ECDHE-RSA-AES128-GCM-SHA256", "authentication_type": "AuthHeader", "host_header": "awsexamplebucket1.s3.us-west-1.amazonaws.com", "tls_version": "TLSV1.1" } { "index": 2, "bucket_owner": "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be", "bucket": "awsexamplebucket1", "time": "[06/Feb/2019:00:00:38 +0000]", "remote_ip": "192.0.2.3", "requester": "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be", "request_id": "891CE47D2EXAMPLE", "operation": "REST.GET.LOGGING_STATUS", "key": "-", "request_uri": "GET /awsexamplebucket1?logging HTTP/1.1", "http_status": "200", "error_code": "-", "bytes_sent": "242", "object_size": "-", "total_time": "11", "turn_around_time": "-", "referer": "-", "user_agent": "S3Console/0.4", "version_id": "-", "host_id": "9vKBE6vMhrNiWHZmb2L0mXOcqPGzQOI5XLnCtZNPxev+Hf+7tpT6sxDwDty4LHBUOZJG96N1234=", "signature_version": "SigV2", "cipher_suite": "ECDHE-RSA-AES128-GCM-SHA256", "authentication_type": "AuthHeader", "host_header": "awsexamplebucket1.s3.us-west-1.amazonaws.com", "tls_version": "TLSV1.1" } { "index": 3, "bucket_owner": "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be", "bucket": "awsexamplebucket1", "time": "[06/Feb/2019:00:00:38 +0000]", "remote_ip": "192.0.2.3", "requester": "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be", "request_id": "A1206F460EXAMPLE", "operation": "REST.GET.BUCKETPOLICY", "key": "-", "request_uri": "GET /awsexamplebucket1?policy HTTP/1.1", "http_status": "404", "error_code": "NoSuchBucketPolicy", "bytes_sent": "297", "object_size": "-", "total_time": "38", "turn_around_time": "-", "referer": "-", "user_agent": "S3Console/0.4", "version_id": "-", "host_id": "BNaBsXZQQDbssi6xMBdBU2sLt+Yf5kZDmeBUP35sFoKa3sLLeMC78iwEIWxs99CRUrbS4n11234=", "signature_version": "SigV2", "cipher_suite": "ECDHE-RSA-AES128-GCM-SHA256", "authentication_type": "AuthHeader", "host_header": "awsexamplebucket1.s3.us-west-1.amazonaws.com", "tls_version": "TLSV1.1" } { "index": 4, "bucket_owner": "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be", "bucket": "awsexamplebucket1", "time": "[06/Feb/2019:00:01:00 +0000]", "remote_ip": "192.0.2.3", "requester": "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be", "request_id": "7B4A0FABBEXAMPLE", "operation": "REST.GET.VERSIONING", "key": "-", "request_uri": "GET /awsexamplebucket1?versioning HTTP/1.1", "http_status": "200", "error_code": "-", "bytes_sent": "113", "object_size": "-", "total_time": "33", "turn_around_time": "-", "referer": "-", "user_agent": "S3Console/0.4", "version_id": "-", "host_id": "Ke1bUcazaN1jWuUlPJaxF64cQVpUEhoZKEG/hmy/gijN/I1DeWqDfFvnpybfEseEME/u7ME1234=", "signature_version": "SigV2", "cipher_suite": "ECDHE-RSA-AES128-GCM-SHA256", "authentication_type": "AuthHeader", "host_header": "awsexamplebucket1.s3.us-west-1.amazonaws.com", "tls_version": "TLSV1.1" } { "index": 5, "bucket_owner": "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be", "bucket": "awsexamplebucket1", "time": "[06/Feb/2019:00:01:57 +0000]", "remote_ip": "192.0.2.3", "requester": "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be", "request_id": "DD6CC733AEXAMPLE", "operation": "REST.PUT.OBJECT", "key": "s3-dg.pdf", "request_uri": "PUT /awsexamplebucket1/s3-dg.pdf HTTP/1.1", "http_status": "200", "error_code": "-", "bytes_sent": "-", "object_size": "4406583", "total_time": "41754", "turn_around_time": "28", "referer": "-", "user_agent": "S3Console/0.4", "version_id": "-", "host_id": "10S62Zv81kBW7BB6SX4XJ48o6kpcl6LPwEoizZQQxJd5qDSCTLX0TgS37kYUBKQW3+bPdrg1234=", "signature_version": "SigV4", "cipher_suite": "ECDHE-RSA-AES128-SHA", "authentication_type": "AuthHeader", "host_header": "awsexamplebucket1.s3.us-west-1.amazonaws.com", "tls_version": "TLSV1.1" } { "total": 5, "matched": 5, "unmatched": 0, "skipped": 0, "source": "sample_s3.log", "errors": null }
特定の行を読み飛ばす
ヘッダーを読み飛ばしたい場合などは --skip
, -s
オプションが使えます。行番号をカンマ区切りで渡します。
alpen cf --file-path testdata/log/sample_cf.log --skip 1,2
ZIP の中身を直接解析する
ZIP を直接読む場合は --zip-path
, -z
でパスを渡します。中身のファイルをすべて読ませたくない場合は、--glob-pattern
, -G
オプションを使って除外できます。
alpen alb --zip-path testdata/zip/sample_alb.log.zip --glob-pattern *.log
シェル補完について
シェル補完にも対応しています。対応しているシェルは bash
, zsh
, pwsh
です。以下のコマンドでスクリプトが標準出力に表示されるのでファイルにリダイレクトしておき、シェル起動時に所定の方法で読み込ませてください。
alpen --completion bash
コマンドラインパーサーについて
コマンドラインでの引数解析を実現するためのライブラリとして、今回 github.com/urfave/cli/v2
を使いました。多少オーバースペックかなと思いましたが、簡単に CLI アプリを実現できて便利でした。シェル補完スクリプトの対応もこのライブラリの機能を利用しています。
正規表現パターン
解析のための正規表現パターンはコードを見ていただいたほうがよいかと思います。
今後の展望
実現難易度はまだ調べていませんが、以下をサポートできればと考えています。手元でアクセスログ調査を行う際の汎用的なツールという位置付けにできればいいなと思っています。
- Apache common log format
- Apache common log format (with vhost)
- Apache combined log format
また、外部ファイルから正規表現パターンを読ませる機能があれば独自のログ形式を解析できますし、text/template
を使えば出力もカスタマイズできるはずなので、作る側の気力次第では割と汎用的なツールに育つかもしれません。
おわりに
AWS のアクセスログを解析する CLI ツールについて紹介しました。まだ破壊的変更が入る可能性はありますが、よろしければ使ってください。
このツールの作成を通じて Go 製 CLI アプリの CI 手法やバイナリのリリースを自動化する方法も学べたので、そちらも別記事で紹介したいと思います。