🐥

gostry で PostgreSQL の行履歴を Go から軽量にキャプチャする

に公開

この記事は ChatGPT を用いて書かれた

gostryとは

gostry は、database/sql トランザクションをラップして PostgreSQL の行履歴を自動で記録する、軽量なGo ライブラリです。INSERT / UPDATE / DELETE をフックして RETURNING 付きで行イメージを取得し、同一トランザクション内で履歴テーブルへ書き込む仕組みを提供します。

使ってみる

1. Handler をセットアップ

handler := gostry.New(gostry.Config{
HistorySuffix:       "_history",
SkipIfNotExists:     true,
AutoAttachReturning: true,
})
wrapped := handler.Wrap(db)
  • HistorySuffix ... ベーステーブル名につけるサフィックス。デフォルトは _history
  • AutoAttachReturning ... RETURNING のない DML に対し RETURNING * を自動付与(PostgreSQL 専用)。
  • SkipIfNotExists ... 履歴テーブルがまだ存在しない場合の挿入をスキップ。

コンテキストに operator / traceID / reason を載せると、履歴テーブルにそのまま保存されます。

ctx := gostry.WithOperator(context.Background(), "cli-user")
ctx = gostry.WithTraceID(ctx, "trace-demo-001")
ctx = gostry.WithReason(ctx, "demo run")

2. トランザクションを実行

tx, _ := wrapped.BeginTx(ctx, nil)
defer tx.Rollback()

// RETURNING なしでも OK(AutoAttachReturning が有効な場合)
_, _ = tx.ExecContext(ctx, `UPDATE orders SET status='paid' WHERE id=$1`, orderID)

// 監査対象外にしたいクエリは WithSkip で除外
skipCtx := gostry.WithSkip(ctx)
_, _ = tx.ExecContext(skipCtx, `DELETE FROM temp_table`)

_ = tx.CommitContext(ctx)

履歴テーブル構造の初期化は SchemaConfig + Migrate が便利です(既存テーブルの型を introspection して履歴テーブルを作成)。構造体に
TableName() を実装していれば、そこからテーブル名解決も可能です。

cfg := gostry.SchemaConfig{HistorySuffix: "_history", CreateIDIndex: true}
if err := gostry.Migrate(ctx, db, cfg, Order{}, "payments"); err != nil {
log.Fatal(err)
}

監査テーブルの例

CREATE TABLE orders_history
(
    history_id  BIGSERIAL PRIMARY KEY,
    id          UUID,
    operation   TEXT        NOT NULL,
    operated_at TIMESTAMPTZ NOT NULL,
    operated_by TEXT,
    trace_id    TEXT,
    reason      TEXT,
    before      JSONB,
    after       JSONB
);

期待できる利点

  • アプリの SQL をそのまま利用しつつ、履歴の JSON を行単位で蓄積
  • トリガーや外部イベントストアを持たなくても監査証跡を確保
  • SkipFuncWithSkip で運用中のメンテナンス・バッチを柔軟に除外
  • Postgres 固有の識別子(スキーマ/引用符)もライブラリ側で安全に扱える

注意点

  • AutoAttachReturning はベストエフォートです(ON CONFLICT や複雑なバッチ構文は書き換えず、そのまま実行します)。
  • 行数が多い場合は history_id のような順序キーでマネジメントしたり、CreateIDIndex を有効にするなどの調整が必要です。
  • 履歴テーブルが増えるので、適宜パーティショニングや TTL パージなどのメンテナンスを検討してください。

記事をご覧いただきありがとうございました!フィードバックや Issue 大歓迎です 🙌

Discussion