Skip to main content

Migration Tap

Tap streams migration events while Queen runs. It is useful for debugging, CLI live views, tests, and migration reports.

JSON sink​

sink := tap.NewJSONSink(os.Stdout)
q := queen.New(postgres.New(db), queen.WithTap(sink))

Events include start, exec, transaction lifecycle events, and end.

Capture Go-function SQL​

SQL migrations emit one exec event for the migration SQL. For Go-function migrations, wrap the transaction:

UpFunc: func(ctx context.Context, tx *sql.Tx) error {
t := tap.ObserveTx(ctx, tx)
_, err := t.ExecContext(ctx, `UPDATE users SET email = LOWER(email)`)
return err
}

Analyzer​

sink := tap.NewAnalyzerSink(
tap.NewJSONSink(os.Stdout),
tap.DefaultAnalyzerConfig(),
)

The analyzer adds operation names, normalized SQL templates, bound SQL, slow-query markers, and N+1 detection.

Built-in sinks include NopSink, FuncSink, MultiSink, ChannelSink (non-blocking and drops on overflow), JSONSink, and RecorderSink for in-memory tests. Custom destinations can implement tap.Sink. tap.ObserveTx wraps the transaction Queen already passes to Go functions; it does not create a new transaction. The older tap.Tx helper remains as a deprecated compatibility alias.

Analyzed exec events include the first SQL operation, a normalized template, bound SQL for inspection, slow and N+1 markers, and the statement index within a migration. Programmatic helpers can filter, summarize, and export recorded events:

events := recorder.Events()
filter, _ := tap.ParseFilter("op:select d>100ms slow")
for _, event := range events {
if filter.Match(event) {
fmt.Println(event.BoundSQL)
}
}
summary := tap.Summarize(events)
top := tap.TopQueries(events, "total", 10)
_ = summary
_ = top
_ = tap.WriteMarkdown(os.Stdout, events)

Live CLI​

go run ./cmd/migrate up --tap --driver postgres --dsn "$DATABASE_URL"

Tune thresholds:

go run ./cmd/migrate up --tap \
--tap-slow-threshold 250ms \
--tap-nplus1-threshold 10