Closed22

DuckDB で AWS ALB の S3 ログをクエリするツール作成 with Windsurf

ピン留めされたアイテム
Naoki KOBAYASHINaoki KOBAYASHI

Windsurf + Claude 3.7 sonnet でツールを実装してみた感想。

S3にあるALBログの調査はAthenaよりDuckDBのほうが簡単 - これをコマンドでシュッと呼び出したい!がモチベーション
https://road288.hatenablog.com/entry/2024/11/06/113954

今回は Windsurf にやり切ってもらう!を意識して 95% くらいは Windsurf が実装 & コマンドライン操作(したと思う)。実際仕事で使うよ、、、荒削りなところとか、セキュリティ的な部分はあとで見る...

https://github.com/naotama2002/dalv

  • やりたいことを実装 -> リリースのための GitHub Actions workflow 実装 -> リリース!までのトータルで考えると圧倒的に早い
    • プログラム実装だけであれば自分でやった方がはやかったかも...が、とりあえずやりたいことを実装してもらってそれをベースに修正してくのが一番早そう
    • GitHub Actions workflow 周辺は、空で yaml 書ける変態さん以外はちょー便利、Makefile もとても助かる
  • エラー解消で無限ループに入ることがある
    • Windsurf でやり切ることに拘らず自分で実装した方が早い(良い) / それはそう
  • テスト書いてくれるのめちゃ良い
  • Windsurf に追加して指示したことは、その度に markdown ファイルに書き出しておくと良さそう
  • 消費リクエスト数
Naoki KOBAYASHINaoki KOBAYASHI

Windsurf と一緒にツールを作成するシリーズ? 今回は新規ツール作成するよ。

Naoki KOBAYASHINaoki KOBAYASHI

こんな README.md を作成

dalv

Querying AWS ALB S3 logs with duckdb

DuckDB で AWS ALB の S3 ログを読み込むための準備

DuckDB で AWS ALB S3 logs をクエリするためのセットアップと、必要なテーブル作成

INSTALL aws;
LOAD aws;
INSTALL httpfs;
LOAD httpfs;
CREATE SECRET (
    TYPE S3,
    PROVIDER CREDENTIAL_CHAIN
);

ログを読み込みためのテーブル作成

CREATE TABLE alb_log_20250303 AS
SELECT *
FROM read_csv(
    's3://{S3_BUCKET_NAME}/xxxxxx/AWSLogs/{ACCOUNT_ID}/elasticloadbalancing/{REGION}/2025/03/03/*.log.gz',
    columns={
        'type': 'VARCHAR',
        'timestamp': 'TIMESTAMP',
        'elb': 'VARCHAR',
        'client_ip_port': 'VARCHAR',
        'target_ip_port': 'VARCHAR',
        'request_processing_time': 'DOUBLE',
        'target_processing_time': 'DOUBLE',
        'response_processing_time': 'DOUBLE',
        'elb_status_code': 'INTEGER',
        'target_status_code': 'VARCHAR',
        'received_bytes': 'BIGINT',
        'sent_bytes': 'BIGINT',
        'request': 'VARCHAR',
        'user_agent': 'VARCHAR',
        'ssl_cipher': 'VARCHAR',
        'ssl_protocol': 'VARCHAR',
        'target_group_arn': 'VARCHAR',
        'trace_id': 'VARCHAR',
        'domain_name': 'VARCHAR',
        'chosen_cert_arn': 'VARCHAR',
        'matched_rule_priority': 'VARCHAR',
        'request_creation_time': 'TIMESTAMP',
        'actions_executed': 'VARCHAR',
        'redirect_url': 'VARCHAR',
        'error_reason': 'VARCHAR',
        'target_port_list': 'VARCHAR',
        'target_status_code_list': 'VARCHAR',
        'classification': 'VARCHAR',
        'classification_reason': 'VARCHAR',
        'conn_trace_id': 'VARCHAR'
    },
    delim=' ',
    quote='"',
    escape='"',
    header=False,
    auto_detect=False
);

DuckDB で AWS ALB の S3 ログをクエリする

select * from alb_log_20250303 where elb_status_code != 431;
Naoki KOBAYASHINaoki KOBAYASHI

Windsurf に README.md をみてツールの仕様を考えてもらう

README.md に書かれていることを

dalv s3://{S3_BUCKET_NAME}/xxxxxx/AWSLogs/{ACCOUNT_ID}/elasticloadbalancing/{REGION}/2025/03/03/*.log.gz

のように S3 バケットを指定して起動する。

起動後は DuckDB のコンソール操作をしてクエリできるツールを作りたいと思います。

開発言語は Go言語 です。

docs/too-spec.md としてツールの仕様を書き出してください。
Naoki KOBAYASHINaoki KOBAYASHI

なんかええ感じの仕様が作成されたねー、ほんまに作成できるの?


dalv - DuckDB AWS ALB Log Viewer

dalv is a Go-based command-line tool for querying AWS Application Load Balancer (ALB) logs stored in S3 buckets using DuckDB.

機能概要

  • S3 バケットから AWS ALB ログを直接クエリ
  • DuckDB を使用した強力なSQL機能を提供
  • インタラクティブなコンソールモードをサポート
  • 簡単なコマンドライン操作

コマンド仕様

dalv [options] <s3-path>

引数

  • <s3-path>: 必須。ALB ログが保存されている S3 パスを指定。ワイルドカードの使用可能 (例: s3://bucket-name/path/to/logs/*.log.gz)

オプション

  • -i, --interactive: インタラクティブモードで起動 (デフォルト: true)
  • -q, --query <sql>: 指定された SQL クエリを実行して結果を表示し、終了
  • -o, --output <file>: 結果を指定されたファイルに出力
  • -f, --format <format>: 出力フォーマットを指定 (csv, json, table) (デフォルト: table)
  • --aws-profile <profile>: 使用する AWS プロファイルを指定
  • --region <region>: AWS リージョンを指定
  • --debug: デバッグ情報を表示

内部処理フロー

  1. コマンドライン引数の解析
  2. AWS 認証情報の取得と検証
  3. 指定された S3 パスからログファイルのメタデータ取得
  4. DuckDB インスタンスの初期化
  5. AWS 拡張と httpfs 拡張のインストールと読み込み
  6. S3 アクセスのための Secret 設定
  7. ログデータをクエリするための一時テーブル作成
  8. インタラクティブモードまたは指定クエリの実行
  9. 結果の表示または出力

インタラクティブモード仕様

インタラクティブモードでは、以下の機能を提供:

  • SQL クエリの入力と実行
  • コマンド履歴機能 (上下キーで過去のクエリ呼び出し)
  • クエリ補完機能 (TABキーで補完)
  • ヘルプコマンド (.help)
  • 終了コマンド (.quit または .exit)
  • テーブル一覧表示 (.tables)
  • テーブル構造表示 (.schema <table_name>)
  • キーワード色分け表示

実装要件

技術スタック

  • Go言語 (1.18以上)
  • DuckDB Go ドライバー (github.com/marcboeker/go-duckdb)
  • AWS SDK for Go v2
  • Cobra (コマンドライン引数解析)
  • Prompter (インタラクティブモード用)

モジュール構成

dalv/
├── cmd/            # コマンドライン処理
│   └── root.go     # メインのコマンド定義
├── internal/       # 内部パッケージ
│   ├── aws/        # AWS 関連処理
│   ├── console/    # インタラクティブコンソール処理
│   ├── duckdb/     # DuckDB 連携処理
│   └── query/      # クエリ実行・結果整形処理
├── pkg/            # 外部公開可能なパッケージ
├── main.go         # エントリポイント
└── go.mod          # Go モジュール定義

ユースケース例

基本的な使用方法

# インタラクティブモードで起動
dalv s3://chatgai-prod-211125472860/chatgai-prod/AWSLogs/211125472860/elasticloadbalancing/ap-northeast-1/2025/03/03/*.log.gz

# 特定のクエリを実行して終了
dalv -q "SELECT COUNT(*) FROM alb_log WHERE elb_status_code = 200" s3://bucket/path/*.log.gz

# 結果をCSVファイルに出力
dalv -q "SELECT * FROM alb_log LIMIT 100" -o results.csv -f csv s3://bucket/path/*.log.gz

# 特定のAWSプロファイルを使用
dalv --aws-profile production s3://bucket/path/*.log.gz

インタラクティブモードでの操作例

dalv> SELECT COUNT(*) FROM alb_log;
┌───────────┐
│ count_star │
├───────────┤
│      1234 │
└───────────┘

dalv> SELECT elb_status_code, COUNT(*) as count FROM alb_log GROUP BY elb_status_code ORDER BY count DESC;
┌───────────────┬───────┐
│ elb_status_code│ count │
├───────────────┼───────┤
│           200 │   980 │
│           404 │   120 │
│           500 │    80 │
│           403 │    54 │
└───────────────┴───────┘

dalv> .tables
┌────────┐
│  name  │
├────────┤
│ alb_log │
└────────┘

dalv> .exit

今後の拡張性

  • クエリ結果のグラフ表示機能
  • ログパターンの自動検出と分析
  • 一般的なクエリテンプレートの提供
  • 複数バケット・パスの同時クエリ対応
  • クエリ結果のキャッシュ機能
  • カスタムUDF(ユーザー定義関数)のサポート

実装計画

  1. プロジェクト基本構造とコマンドライン引数処理の実装
  2. AWS 認証と S3 パス解析機能の実装
  3. DuckDB 連携処理の実装
  4. インタラクティブコンソールの実装
  5. クエリ実行と結果表示処理の実装
  6. テスト・ドキュメント作成
  7. リリース準備
Naoki KOBAYASHINaoki KOBAYASHI

作ってもらった仕様書にもとづいて実装してもらおう

できたの?

README.md をええ感じにするのとビルドスクリプト(何で書いてくれるんだろう)をお願いしたよ

シェルスクリプト(確かに)だったので

Makefile を用意してもらう

Naoki KOBAYASHINaoki KOBAYASHI

ソースコードできた!

それでビルド&実行できるんですか?

この後いろいろ試した後、 running だったかな?の表示のまま で返答が返ってこなくなったのでキャンセル

どれどれ

ふむ Explan してお話し開始

いやだ、DuckDB 公式ページにあるライブラリがいい。公式ドライバ使用するかい? go get github.com/duckdb/duckdb-go ってそんなライブラリ存在しないぞ!

go get github.com/marcboeker/go-duckdb@v1.4.0

してバージョンダウンを勧められるんだけど、その理由はなんでなんだろう?

あーね、やばい、そろそろ気持ちが切れてきた。

検索してみるとなんか出てくるなー。最後まで Windsurf さんで実装しきりたいんだよな。全部捨てて Deno で実装するか!
https://github.com/marcboeker/go-duckdb/issues/275

Naoki KOBAYASHINaoki KOBAYASHI

これが生成 AI 時代のプログラミングなんじゃね?🙃

ほんまに?俺 Deno 全くわからんけど、よし!

ビルドして

僕は mise でツール管理したいんだよ

なるほど? deno の最新版は mise 環境にインストールされている。

が、mise って ~/.zshrc で active にしてるけどこれが効かないのか?

eval "$(~/.local/bin/mise activate zsh)"

deno のパスを教えちゃお

ビルド走ったねー、いや、僕の力が入ってしまった、ダメ、我慢

Naoki KOBAYASHINaoki KOBAYASHI

いや、Done じゃねーじゃん、面白い

頑張って、頑張ると、全てを忘れて、ビルドも通ってないし、deno のパスも忘れちゃった

Naoki KOBAYASHINaoki KOBAYASHI

わーん、これは仕様書がよくばりすぎるのか?僕はもっとシンプルなものでよかったんだよ。

Naoki KOBAYASHINaoki KOBAYASHI

DuckDB + Deno での実装....ギブアップ! Deno でのビルド成功せず.... これ以上 Windsurf のクレジット消費はもったいないな。

最初 README.md に書かれていたことを実現するために、僕なら

  • DuckDB は brew なりなんなりで OS にインストールしてもらう前提とする
  • aws, httpfs のロードと S3 SECETS 作成 + AWS ALB S3 (.tar.gz) ログをテーブル化するための SQL? を組み立てる
    • ロードする S3 バケット(.tar.gz) だけ外から与えられるようにする

で実現できるよなー、そうするか!と思うよね。これって今の AI エディタでの開発だと知識として与えることになるだろうな、Devin でも同様かな?

Naoki KOBAYASHINaoki KOBAYASHI

やり直し!

docs/tool-spec.md の仕様を変更します。

やりたいことは

dalv s3://{ALBログファイル.targzパス}

なので同じ。
プログラミング言語で全て実装するのではなく、duckdb は事前にインストールされていることを前提にする。

- aws, httpfs のロードと S3 SECETS 作成 + AWS ALB S3 (.tar.gz) ログをテーブル化するための SQL? を組み立てる
- ロードする S3 バケット(.tar.gz) だけ外から与えられるようにする

という戦略に変更したいと思います。duckdb を適切な呼び出しをすることで、やりたいことを実現してください。

箇条書きしたやりたいことに必要な情報は READMD.md を参照して!
ツールは Go 言語を使って実現してください。
Naoki KOBAYASHINaoki KOBAYASHI

ごめん!ちゃんと docs/tool-spec.md を書いて!ってお願いしなかったね

duckdb コマンド実行前提なのか?確認してみたけど自信あるみたいだね

Naoki KOBAYASHINaoki KOBAYASHI

できたらしいぞ!

Go 言語で開発するは Makefile 書いて!ってのが僕のルールなのか、そうだね

.gitignore, .tool-versions も修正してもらう

Naoki KOBAYASHINaoki KOBAYASHI

CI 作成しよう

pull request 時の CI一式と、Upload Artifacts の 2つの workflow を作成してもらった。


初めての git 操作依頼! この PR. のブランチを作成

https://github.com/naotama2002/dalv/pull/1

エラーが発生したので修正依頼
https://github.com/naotama2002/dalv/actions/runs/13749380408

CI 通ったね
https://github.com/naotama2002/dalv/actions/runs/13749425567

PR#1 をマージ! もう一つの workflow が走るよ
https://github.com/naotama2002/dalv/actions/runs/13749442747
成功してるね!

Naoki KOBAYASHINaoki KOBAYASHI

Windsurf が実施したことに対して、追加で指示したことを Rules として書いておきたいよなーと思ったけど、途中で死んだり、Windsurf 再起動してるからダメだった、都度都度書き出さないとダメだね。

Naoki KOBAYASHINaoki KOBAYASHI

Go 実装

  • テストに関すること

    • 常にテストが通る状態を保って
    • ファイルを追加したらテストを実装して
    • 関数を変更したらテストが通るか?確認してテストを修正して、また、追加機能があればテストを追加して
    • テストは1ファイルずつテスト実行しながら確認すること
  • 機能実装時

    • 機能追加・変更・削除で README.md に変更が必要ないか?確認して必要があれば修正して

このくらいか?優秀

このスクラップは2025/03/15にクローズされました